Fix some more variable-set-but-not-used compiler warnings
[platform/upstream/gstreamer.git] / ext / opencv / gstmotioncells.c
1 /*
2  * GStreamer MotioCells detect areas of motion
3  * Copyright (C) 2011 Robert Jobbagy <jobbagy.robert@gmail.com>
4  * Copyright (C) 2011 Nicola Murino <nicola.murino@gmail.com>
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Alternatively, the contents of this file may be used under the
25  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26  * which case the following provisions apply instead of the ones
27  * mentioned above:
28  *
29  * This library is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU Library General Public
31  * License as published by the Free Software Foundation; either
32  * version 2 of the License, or (at your option) any later version.
33  *
34  * This library is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37  * Library General Public License for more details.
38  *
39  * You should have received a copy of the GNU Library General Public
40  * License along with this library; if not, write to the
41  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
42  * Boston, MA 02111-1307, USA.
43  */
44
45 /**
46  * SECTION:element-motioncells
47  *
48  * Performs motion detection on videos.
49  *
50  * <refsect2>
51  * <title>Example launch line</title>
52  * |[
53  * gst-launch-0.10 videotestsrc pattern=18 ! videorate ! videoscale ! video/x-raw-yuv,width=320,height=240,framerate=5/1 ! ffmpegcolorspace ! motioncells ! ffmpegcolorspace ! xvimagesink
54  * ]|
55  * </refsect2>
56  */
57
58 #ifdef HAVE_CONFIG_H
59 #  include <config.h>
60 #endif
61
62 #include <stdio.h>
63 #include <string.h>
64 #include <glib.h>
65 #include "gstmotioncells.h"
66 #include "motioncells_wrapper.h"
67 #include <sys/time.h>
68 #include <time.h>
69 #include <limits.h>
70
71 GST_DEBUG_CATEGORY_STATIC (gst_motion_cells_debug);
72 #define GST_CAT_DEFAULT gst_motion_cells_debug
73
74 #define GRID_DEF 10
75 #define GRID_MIN 8
76 #define GRID_MAX 32
77 #define SENSITIVITY_DEFAULT 0.5
78 #define SENSITIVITY_MIN 0
79 #define SENSITIVITY_MAX 1
80 #define THRESHOLD_MIN 0
81 #define THRESHOLD_DEFAULT 0.01
82 #define THRESHOLD_MAX 1.0
83 #define GAP_MIN 1
84 #define GAP_DEF 5
85 #define GAP_MAX 60
86 #define POST_NO_MOTION_MIN 0
87 #define POST_NO_MOTION_DEF 0
88 #define POST_NO_MOTION_MAX 180
89 #define MINIMUM_MOTION_FRAMES_MIN 1
90 #define MINIMUM_MOTION_FRAMES_DEF 1
91 #define MINIMUM_MOTION_FRAMES_MAX 60
92 #define THICKNESS_MIN -1
93 #define THICKNESS_DEF 1
94 #define THICKNESS_MAX 5
95 #define DATE_MIN 0
96 #define DATE_DEF 1
97 #define DATE_MAX LONG_MAX
98 #define DEF_DATAFILEEXT "vamc"
99 #define MSGLEN 6
100 #define BUSMSGLEN 20
101
102 #define GFREE(POINTER)\
103                 {\
104                         g_free(POINTER);\
105                         POINTER = NULL;\
106                 }
107
108 int instanceCounter = 0;
109 gboolean element_id_was_max = false;
110
111 /* Filter signals and args */
112 enum
113 {
114   /* FILL ME */
115   LAST_SIGNAL
116 };
117
118 enum
119 {
120   PROP_0,
121   PROP_GRID_X,
122   PROP_GRID_Y,
123   PROP_SENSITIVITY,
124   PROP_THRESHOLD,
125   PROP_DISPLAY,
126   PROP_DATE,
127   PROP_DATAFILE,
128   PROP_DATAFILE_EXT,
129   PROP_MOTIONMASKCOORD,
130   PROP_MOTIONMASKCELLSPOS,
131   PROP_CELLSCOLOR,
132   PROP_MOTIONCELLSIDX,
133   PROP_GAP,
134   PROP_POSTNOMOTION,
135   PROP_MINIMUNMOTIONFRAMES,
136   PROP_CALCULATEMOTION,
137   PROP_POSTALLMOTION,
138   PROP_USEALPHA,
139   PROP_MOTIONCELLTHICKNESS
140 };
141
142 /* the capabilities of the inputs and outputs.
143  */
144 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
145     GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-rgb"));
146
147 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
148     GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-rgb"));
149
150 GST_BOILERPLATE (GstMotioncells, gst_motion_cells, GstElement,
151     GST_TYPE_ELEMENT);
152
153 static void gst_motion_cells_set_property (GObject * object, guint prop_id,
154     const GValue * value, GParamSpec * pspec);
155 static void gst_motion_cells_get_property (GObject * object, guint prop_id,
156     GValue * value, GParamSpec * pspec);
157
158 static gboolean gst_motion_cells_set_caps (GstPad * pad, GstCaps * caps);
159 static GstFlowReturn gst_motion_cells_chain (GstPad * pad, GstBuffer * buf);
160
161 static void gst_motioncells_update_motion_cells (GstMotioncells * filter);
162 static void gst_motioncells_update_motion_masks (GstMotioncells * filter);
163
164 /* Clean up */
165 static void
166 gst_motion_cells_finalize (GObject * obj)
167 {
168   GstMotioncells *filter = gst_motion_cells (obj);
169
170   motion_cells_free (filter->id);
171
172   //freeing previously allocated dynamic array
173   if (filter->motionmaskcoord_count > 0) {
174     GFREE (filter->motionmaskcoords);
175   }
176
177   if (filter->motionmaskcells_count > 0) {
178     GFREE (filter->motionmaskcellsidx);
179   }
180   if (filter->motioncells_count > 0) {
181     GFREE (filter->motioncellsidx);
182   }
183
184   if (filter->cvImage) {
185     cvReleaseImage (&filter->cvImage);
186   }
187
188   GFREE (filter->motioncellscolor);
189   GFREE (filter->prev_datafile);
190   GFREE (filter->cur_datafile);
191   GFREE (filter->basename_datafile);
192   GFREE (filter->datafile_extension);
193
194   g_mutex_free (filter->propset_mutex);
195
196   G_OBJECT_CLASS (parent_class)->finalize (obj);
197 }
198
199 /* GObject vmethod implementations */
200 static void
201 gst_motion_cells_base_init (gpointer gclass)
202 {
203   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
204
205   gst_element_class_set_details_simple (element_class,
206       "motioncells",
207       "Filter/Effect/Video",
208       "Performs motion detection on videos and images, providing detected motion cells index via bus messages",
209       "Robert Jobbagy <jobbagy dot robert at gmail dot com>, Nicola Murino <nicola dot murino at gmail.com>");
210
211   gst_element_class_add_pad_template (element_class,
212       gst_static_pad_template_get (&src_factory));
213   gst_element_class_add_pad_template (element_class,
214       gst_static_pad_template_get (&sink_factory));
215 }
216
217 /* initialize the motioncells's class */
218 static void
219 gst_motion_cells_class_init (GstMotioncellsClass * klass)
220 {
221   GObjectClass *gobject_class;
222
223   gobject_class = (GObjectClass *) klass;
224   parent_class = g_type_class_peek_parent (klass);
225
226   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_motion_cells_finalize);
227   gobject_class->set_property = gst_motion_cells_set_property;
228   gobject_class->get_property = gst_motion_cells_get_property;
229
230   g_object_class_install_property (gobject_class, PROP_GRID_X,
231       g_param_spec_int ("gridx", "Number of Horizontal Grids",
232           "You can give number of horizontal grid cells.", GRID_MIN, GRID_MAX,
233           GRID_DEF, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
234   g_object_class_install_property (gobject_class, PROP_GRID_Y,
235       g_param_spec_int ("gridy", "Number of Vertical Grids",
236           "You can give number of vertical grid cells.", GRID_MIN, GRID_MAX,
237           GRID_DEF, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
238   g_object_class_install_property (gobject_class, PROP_SENSITIVITY,
239       g_param_spec_double ("sensitivity", "Motion Sensitivity",
240           "You can tunning the element motion sensitivity.", SENSITIVITY_MIN,
241           SENSITIVITY_MAX, SENSITIVITY_DEFAULT,
242           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243   g_object_class_install_property (gobject_class, PROP_THRESHOLD,
244       g_param_spec_double ("threshold", "Lower bound of motion cells number",
245           "Threshold value for motion, when motion cells number greater sum cells * threshold, we show motion.",
246           THRESHOLD_MIN, THRESHOLD_MAX, THRESHOLD_DEFAULT,
247           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
248   g_object_class_install_property (gobject_class, PROP_GAP,
249       g_param_spec_int ("gap",
250           "Gap is time in second, elapsed time from last motion timestamp. ",
251           "If elapsed time minus form last motion timestamp is greater or equal than gap then we post motion finished bus message. ",
252           GAP_MIN, GAP_MAX, GAP_DEF,
253           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
254   g_object_class_install_property (gobject_class, PROP_POSTNOMOTION,
255       g_param_spec_int ("postnomotion", "POSTNOMOTION",
256           "If non 0 post a no_motion event is posted on the bus if no motion is detected for N seconds",
257           POST_NO_MOTION_MIN, POST_NO_MOTION_MAX, POST_NO_MOTION_DEF,
258           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
259   g_object_class_install_property (gobject_class, PROP_MINIMUNMOTIONFRAMES,
260       g_param_spec_int ("minimummotionframes", "MINIMUN MOTION FRAMES",
261           "Define the minimum number of motion frames that trigger a motion event",
262           MINIMUM_MOTION_FRAMES_MIN, MINIMUM_MOTION_FRAMES_MAX,
263           MINIMUM_MOTION_FRAMES_DEF,
264           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
265   g_object_class_install_property (gobject_class, PROP_DISPLAY,
266       g_param_spec_boolean ("display", "Display",
267           "Motion Cells visible or not on Current Frame", FALSE,
268           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
269   g_object_class_install_property (gobject_class, PROP_POSTALLMOTION,
270       g_param_spec_boolean ("postallmotion", "Post All Motion",
271           "Element post bus msg for every motion frame or just motion start and motion stop",
272           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
273   g_object_class_install_property (gobject_class, PROP_USEALPHA,
274       g_param_spec_boolean ("usealpha", "Use alpha",
275           "Use or not alpha blending on frames with motion cells", TRUE,
276           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
277   g_object_class_install_property (gobject_class, PROP_DATE,
278       g_param_spec_long ("date", "Motion Cell Date",
279           "Current Date in milliseconds", DATE_MIN, DATE_MAX, DATE_DEF,
280           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281   g_object_class_install_property (gobject_class, PROP_DATAFILE,
282       g_param_spec_string ("datafile", "DataFile",
283           "Location of motioncells data file (empty string means no saving)",
284           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
285   g_object_class_install_property (gobject_class, PROP_DATAFILE_EXT,
286       g_param_spec_string ("datafileextension", "DataFile Extension",
287           "Extension of datafile", DEF_DATAFILEEXT,
288           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
289   g_object_class_install_property (gobject_class, PROP_MOTIONMASKCOORD,
290       g_param_spec_string ("motionmaskcoords", "Motion Mask with Coordinates",
291           "The upper left x, y and lower right x, y coordinates separated with \":\", "
292           "describe a region. Regions separated with \",\"", NULL,
293           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294   g_object_class_install_property (gobject_class, PROP_MOTIONMASKCELLSPOS,
295       g_param_spec_string ("motionmaskcellspos",
296           "Motion Mask with Cells Position",
297           "The line and column idx separated with \":\" what cells want we mask-out, "
298           "describe a cell. Cells separated with \",\"", NULL,
299           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
300   g_object_class_install_property (gobject_class, PROP_CELLSCOLOR,
301       g_param_spec_string ("cellscolor", "Color of Motion Cells",
302           "The color of motion cells separated with \",\"", "255,255,0",
303           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
304   g_object_class_install_property (gobject_class, PROP_MOTIONCELLSIDX,
305       g_param_spec_string ("motioncellsidx", "Motion Cells Of Interest(MOCI)",
306           "The line and column idx separated with \":\", "
307           "describe a cell. Cells separated with \",\"", NULL,
308           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
309   g_object_class_install_property (gobject_class, PROP_CALCULATEMOTION,
310       g_param_spec_boolean ("calculatemotion", "Calculate Motion",
311           "If needs calculate motion on frame you need this property setting true otherwise false",
312           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
313   g_object_class_install_property (gobject_class, PROP_MOTIONCELLTHICKNESS,
314       g_param_spec_int ("motioncellthickness", "Motion Cell Thickness",
315           "Motion Cell Border Thickness, if it's -1 then motion cell will be fill",
316           THICKNESS_MIN, THICKNESS_MAX, THICKNESS_DEF,
317           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
318 }
319
320 /* initialize the new element
321  * instantiate pads and add them to element
322  * set pad callback functions
323  * initialize instance structure
324  */
325 static void
326 gst_motion_cells_init (GstMotioncells * filter, GstMotioncellsClass * gclass)
327 {
328   filter->propset_mutex = g_mutex_new ();
329   filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
330   gst_pad_set_setcaps_function (filter->sinkpad,
331       GST_DEBUG_FUNCPTR (gst_motion_cells_set_caps));
332   gst_pad_set_getcaps_function (filter->sinkpad,
333       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
334   gst_pad_set_chain_function (filter->sinkpad,
335       GST_DEBUG_FUNCPTR (gst_motion_cells_chain));
336
337   filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
338   gst_pad_set_getcaps_function (filter->srcpad,
339       GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
340
341   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
342   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
343
344   filter->display = TRUE;
345   filter->calculate_motion = TRUE;
346
347   filter->prevgridx = 0;
348   filter->prevgridy = 0;
349   filter->gridx = GRID_DEF;
350   filter->gridy = GRID_DEF;
351   filter->gap = GAP_DEF;
352   filter->postnomotion = POST_NO_MOTION_DEF;
353   filter->minimum_motion_frames = MINIMUM_MOTION_FRAMES_DEF;
354
355   filter->prev_datafile = g_strdup (NULL);
356   filter->cur_datafile = g_strdup (NULL);
357   filter->basename_datafile = g_strdup (NULL);
358   filter->datafile_extension = g_strdup (DEF_DATAFILEEXT);
359   filter->sensitivity = SENSITIVITY_DEFAULT;
360   filter->threshold = THRESHOLD_DEFAULT;
361
362   filter->motionmaskcoord_count = 0;
363   filter->motionmaskcoords = NULL;
364   filter->motionmaskcells_count = 0;
365   filter->motionmaskcellsidx = NULL;
366   filter->motioncellscolor = g_new0 (cellscolor, 1);
367   filter->motioncellscolor->R_channel_value = 255;
368   filter->motioncellscolor->G_channel_value = 255;
369   filter->motioncellscolor->B_channel_value = 0;
370   filter->motioncellsidx = NULL;
371   filter->motioncells_count = 0;
372   filter->motion_begin_timestamp = 0;
373   filter->last_motion_timestamp = 0;
374   filter->last_nomotion_notified = 0;
375   filter->consecutive_motion = 0;
376   filter->motion_timestamp = 0;
377   filter->prev_buff_timestamp = 0;
378   filter->cur_buff_timestamp = 0;
379   filter->diff_timestamp = -1;
380   gettimeofday (&filter->tv, NULL);
381   filter->starttime = 1000 * filter->tv.tv_sec;
382   filter->previous_motion = false;
383   filter->changed_datafile = false;
384   filter->postallmotion = false;
385   filter->usealpha = true;
386   filter->firstdatafile = false;
387   filter->firstgridx = true;
388   filter->firstgridy = true;
389   filter->changed_gridx = false;
390   filter->changed_gridy = false;
391   filter->firstframe = true;
392   filter->changed_startime = false;
393   filter->sent_init_error_msg = false;
394   filter->sent_save_error_msg = false;
395   filter->thickness = THICKNESS_DEF;
396
397   filter->datafileidx = 0;
398   g_mutex_lock (filter->propset_mutex);
399   filter->id = instanceCounter;
400   motion_cells_init ();
401   g_mutex_unlock (filter->propset_mutex);
402
403 }
404
405 static void
406 gst_motion_cells_set_property (GObject * object, guint prop_id,
407     const GValue * value, GParamSpec * pspec)
408 {
409   GstMotioncells *filter = gst_motion_cells (object);
410   //variables for overlay regions setup
411   gchar **strs, **colorstr, **motioncellsstr, **motionmaskcellsstr;
412   int i, ux, uy, lx, ly;
413   int r, g, b;
414   int cellscolorscnt = 0;
415   int linidx, colidx, masklinidx, maskcolidx;
416   int tmpux = -1;
417   int tmpuy = -1;
418   int tmplx = -1;
419   int tmply = -1;
420   GstStateChangeReturn ret;
421
422   g_mutex_lock (filter->propset_mutex);
423   switch (prop_id) {
424     case PROP_GRID_X:
425       ret = gst_element_get_state (GST_ELEMENT (filter),
426           &filter->state, NULL, 250 * GST_NSECOND);
427       filter->gridx = g_value_get_int (value);
428       if (filter->prevgridx != filter->gridx
429           && ret == GST_STATE_CHANGE_SUCCESS
430           && filter->state == GST_STATE_PLAYING) {
431         filter->changed_gridx = true;
432       }
433       filter->prevgridx = filter->gridx;
434       break;
435     case PROP_GRID_Y:
436       ret = gst_element_get_state (GST_ELEMENT (filter),
437           &filter->state, NULL, 250 * GST_NSECOND);
438       filter->gridy = g_value_get_int (value);
439       if (filter->prevgridy != filter->gridy
440           && ret == GST_STATE_CHANGE_SUCCESS
441           && filter->state == GST_STATE_PLAYING) {
442         filter->changed_gridy = true;
443       }
444       filter->prevgridy = filter->gridy;
445       break;
446     case PROP_GAP:
447       filter->gap = g_value_get_int (value);
448       break;
449     case PROP_POSTNOMOTION:
450       filter->postnomotion = g_value_get_int (value);
451       break;
452     case PROP_MINIMUNMOTIONFRAMES:
453       filter->minimum_motion_frames = g_value_get_int (value);
454       break;
455     case PROP_SENSITIVITY:
456       filter->sensitivity = g_value_get_double (value);
457       break;
458     case PROP_THRESHOLD:
459       filter->threshold = g_value_get_double (value);
460       break;
461     case PROP_DISPLAY:
462       filter->display = g_value_get_boolean (value);
463       break;
464     case PROP_POSTALLMOTION:
465       filter->postallmotion = g_value_get_boolean (value);
466       break;
467     case PROP_USEALPHA:
468       filter->usealpha = g_value_get_boolean (value);
469       break;
470     case PROP_CALCULATEMOTION:
471       filter->calculate_motion = g_value_get_boolean (value);
472       break;
473     case PROP_DATE:
474       ret = gst_element_get_state (GST_ELEMENT (filter),
475           &filter->state, NULL, 250 * GST_NSECOND);
476       if (ret == GST_STATE_CHANGE_SUCCESS && filter->state == GST_STATE_PLAYING) {
477         filter->changed_startime = true;
478       }
479       filter->starttime = g_value_get_long (value);
480       break;
481     case PROP_DATAFILE:
482       GFREE (filter->cur_datafile);
483       GFREE (filter->basename_datafile);
484       filter->basename_datafile = g_value_dup_string (value);
485
486       if (strlen (filter->basename_datafile) == 0) {
487         filter->cur_datafile = g_strdup (NULL);
488         break;
489       }
490       filter->cur_datafile =
491           g_strdup_printf ("%s-0.%s", filter->basename_datafile,
492           filter->datafile_extension);
493       if (g_strcmp0 (filter->prev_datafile, filter->basename_datafile) != 0) {
494         filter->changed_datafile = TRUE;
495         filter->sent_init_error_msg = FALSE;
496         filter->sent_save_error_msg = FALSE;
497         filter->datafileidx = 0;
498         motion_cells_free_resources (filter->id);
499       } else {
500         filter->changed_datafile = FALSE;
501       }
502
503       GFREE (filter->prev_datafile);
504       filter->prev_datafile = g_strdup (filter->basename_datafile);
505       break;
506     case PROP_DATAFILE_EXT:
507       GFREE (filter->datafile_extension);
508       filter->datafile_extension = g_value_dup_string (value);
509       break;
510     case PROP_MOTIONMASKCOORD:
511       strs = g_strsplit (g_value_get_string (value), ",", 255);
512       GFREE (filter->motionmaskcoords);
513       //setting number of regions
514       for (filter->motionmaskcoord_count = 0;
515           strs[filter->motionmaskcoord_count] != NULL;
516           ++filter->motionmaskcoord_count);
517       if (filter->motionmaskcoord_count > 0) {
518         sscanf (strs[0], "%d:%d:%d:%d", &tmpux, &tmpuy, &tmplx, &tmply);
519         if (tmpux > -1 && tmpuy > -1 && tmplx > -1 && tmply > -1) {
520           filter->motionmaskcoords =
521               g_new0 (motionmaskcoordrect, filter->motionmaskcoord_count);
522
523           for (i = 0; i < filter->motionmaskcoord_count; ++i) {
524             sscanf (strs[i], "%d:%d:%d:%d", &ux, &uy, &lx, &ly);
525             ux = CLAMP (ux, 0, filter->width - 1);
526             uy = CLAMP (uy, 0, filter->height - 1);
527             lx = CLAMP (lx, 0, filter->width - 1);
528             ly = CLAMP (ly, 0, filter->height - 1);
529             filter->motionmaskcoords[i].upper_left_x = ux;
530             filter->motionmaskcoords[i].upper_left_y = uy;
531             filter->motionmaskcoords[i].lower_right_x = lx;
532             filter->motionmaskcoords[i].lower_right_y = ly;
533           }
534         } else {
535           filter->motionmaskcoord_count = 0;
536         }
537       }
538       if (strs)
539         g_strfreev (strs);
540       tmpux = -1;
541       tmpuy = -1;
542       tmplx = -1;
543       tmply = -1;
544       break;
545     case PROP_MOTIONMASKCELLSPOS:
546       motionmaskcellsstr = g_strsplit (g_value_get_string (value), ",", 255);
547       GFREE (filter->motionmaskcellsidx);
548       //setting number of regions
549       for (filter->motionmaskcells_count = 0;
550           motionmaskcellsstr[filter->motionmaskcells_count] != NULL;
551           ++filter->motionmaskcells_count);
552       if (filter->motionmaskcells_count > 0) {
553         sscanf (motionmaskcellsstr[0], "%d:%d", &tmpux, &tmpuy);
554         if (tmpux > -1 && tmpuy > -1) {
555           filter->motionmaskcellsidx =
556               g_new0 (motioncellidx, filter->motionmaskcells_count);
557           for (i = 0; i < filter->motionmaskcells_count; ++i) {
558             sscanf (motionmaskcellsstr[i], "%d:%d", &masklinidx, &maskcolidx);
559             filter->motionmaskcellsidx[i].lineidx = masklinidx;
560             filter->motionmaskcellsidx[i].columnidx = maskcolidx;
561           }
562         } else {
563           filter->motionmaskcells_count = 0;
564         }
565       }
566       if (motionmaskcellsstr)
567         g_strfreev (motionmaskcellsstr);
568       tmpux = -1;
569       tmpuy = -1;
570       tmplx = -1;
571       tmply = -1;
572       break;
573     case PROP_CELLSCOLOR:
574       colorstr = g_strsplit (g_value_get_string (value), ",", 255);
575       for (cellscolorscnt = 0; colorstr[cellscolorscnt] != NULL;
576           ++cellscolorscnt);
577       if (cellscolorscnt == 3) {
578         sscanf (colorstr[0], "%d", &r);
579         sscanf (colorstr[1], "%d", &g);
580         sscanf (colorstr[2], "%d", &b);
581         //check right RGB color format
582         r = CLAMP (r, 1, 255);
583         g = CLAMP (g, 1, 255);
584         b = CLAMP (b, 1, 255);
585         filter->motioncellscolor->R_channel_value = r;
586         filter->motioncellscolor->G_channel_value = g;
587         filter->motioncellscolor->B_channel_value = b;
588       }
589       if (colorstr)
590         g_strfreev (colorstr);
591       break;
592     case PROP_MOTIONCELLSIDX:
593       motioncellsstr = g_strsplit (g_value_get_string (value), ",", 255);
594
595       //setting number of regions
596       for (filter->motioncells_count = 0;
597           motioncellsstr[filter->motioncells_count] != NULL;
598           ++filter->motioncells_count);
599       if (filter->motioncells_count > 0) {
600         sscanf (motioncellsstr[0], "%d:%d", &tmpux, &tmpuy);
601         if (tmpux > -1 && tmpuy > -1) {
602           GFREE (filter->motioncellsidx);
603
604           filter->motioncellsidx =
605               g_new0 (motioncellidx, filter->motioncells_count);
606
607           for (i = 0; i < filter->motioncells_count; ++i) {
608             sscanf (motioncellsstr[i], "%d:%d", &linidx, &colidx);
609             filter->motioncellsidx[i].lineidx = linidx;
610             filter->motioncellsidx[i].columnidx = colidx;
611           }
612         } else {
613           filter->motioncells_count = 0;
614         }
615       }
616       if (motioncellsstr)
617         g_strfreev (motioncellsstr);
618       tmpux = -1;
619       tmpuy = -1;
620       tmplx = -1;
621       tmply = -1;
622       break;
623     case PROP_MOTIONCELLTHICKNESS:
624       filter->thickness = g_value_get_int (value);
625       break;
626     default:
627       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
628       break;
629   }
630   g_mutex_unlock (filter->propset_mutex);
631 }
632
633 static void
634 gst_motion_cells_get_property (GObject * object, guint prop_id,
635     GValue * value, GParamSpec * pspec)
636 {
637   GstMotioncells *filter = gst_motion_cells (object);
638   GString *str;
639   int i;
640
641   switch (prop_id) {
642     case PROP_GRID_X:
643       g_value_set_int (value, filter->gridx);
644       break;
645     case PROP_GRID_Y:
646       g_value_set_int (value, filter->gridy);
647       break;
648     case PROP_GAP:
649       g_value_set_int (value, filter->gap);
650       break;
651     case PROP_POSTNOMOTION:
652       g_value_set_int (value, filter->postnomotion);
653       break;
654     case PROP_MINIMUNMOTIONFRAMES:
655       g_value_set_int (value, filter->minimum_motion_frames);
656       break;
657     case PROP_SENSITIVITY:
658       g_value_set_double (value, filter->sensitivity);
659       break;
660     case PROP_THRESHOLD:
661       g_value_set_double (value, filter->threshold);
662       break;
663     case PROP_DISPLAY:
664       g_value_set_boolean (value, filter->display);
665       break;
666     case PROP_POSTALLMOTION:
667       g_value_set_boolean (value, filter->postallmotion);
668       break;
669     case PROP_USEALPHA:
670       g_value_set_boolean (value, filter->usealpha);
671       break;
672     case PROP_CALCULATEMOTION:
673       g_value_set_boolean (value, filter->calculate_motion);
674       break;
675     case PROP_DATE:
676       g_value_set_long (value, filter->starttime);
677       break;
678     case PROP_DATAFILE:
679       g_value_set_string (value, filter->basename_datafile);
680       break;
681     case PROP_DATAFILE_EXT:
682       g_value_set_string (value, filter->datafile_extension);
683       break;
684     case PROP_MOTIONMASKCOORD:
685       str = g_string_new ("");
686       for (i = 0; i < filter->motionmaskcoord_count; ++i) {
687         if (i < filter->motionmaskcoord_count - 1)
688           g_string_append_printf (str, "%d:%d:%d:%d,",
689               filter->motionmaskcoords[i].upper_left_x,
690               filter->motionmaskcoords[i].upper_left_y,
691               filter->motionmaskcoords[i].lower_right_x,
692               filter->motionmaskcoords[i].lower_right_y);
693         else
694           g_string_append_printf (str, "%d:%d:%d:%d",
695               filter->motionmaskcoords[i].upper_left_x,
696               filter->motionmaskcoords[i].upper_left_y,
697               filter->motionmaskcoords[i].lower_right_x,
698               filter->motionmaskcoords[i].lower_right_y);
699
700       }
701       g_value_set_string (value, str->str);
702       g_string_free (str, TRUE);
703       break;
704     case PROP_MOTIONMASKCELLSPOS:
705       str = g_string_new ("");
706       for (i = 0; i < filter->motionmaskcells_count; ++i) {
707         if (i < filter->motionmaskcells_count - 1)
708           g_string_append_printf (str, "%d:%d,",
709               filter->motionmaskcellsidx[i].lineidx,
710               filter->motionmaskcellsidx[i].columnidx);
711         else
712           g_string_append_printf (str, "%d:%d",
713               filter->motionmaskcellsidx[i].lineidx,
714               filter->motionmaskcellsidx[i].columnidx);
715       }
716       g_value_set_string (value, str->str);
717       g_string_free (str, TRUE);
718       break;
719     case PROP_CELLSCOLOR:
720       str = g_string_new ("");
721
722       g_string_printf (str, "%d,%d,%d",
723           filter->motioncellscolor->R_channel_value,
724           filter->motioncellscolor->G_channel_value,
725           filter->motioncellscolor->B_channel_value);
726
727       g_value_set_string (value, str->str);
728       g_string_free (str, TRUE);
729       break;
730     case PROP_MOTIONCELLSIDX:
731       str = g_string_new ("");
732       for (i = 0; i < filter->motioncells_count; ++i) {
733         if (i < filter->motioncells_count - 1)
734           g_string_append_printf (str, "%d:%d,",
735               filter->motioncellsidx[i].lineidx,
736               filter->motioncellsidx[i].columnidx);
737         else
738           g_string_append_printf (str, "%d:%d",
739               filter->motioncellsidx[i].lineidx,
740               filter->motioncellsidx[i].columnidx);
741       }
742       g_value_set_string (value, str->str);
743       g_string_free (str, TRUE);
744       break;
745     case PROP_MOTIONCELLTHICKNESS:
746       g_value_set_int (value, filter->thickness);
747       break;
748     default:
749       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
750       break;
751   }
752 }
753
754 static void
755 gst_motioncells_update_motion_cells (GstMotioncells * filter)
756 {
757   int i = 0;
758   int cellscnt = 0;
759   int j = 0;
760   int newcellscnt;
761   motioncellidx *motioncellsidx;
762   for (i = 0; i < filter->motioncells_count; i++) {
763     if ((filter->gridx <= filter->motioncellsidx[i].columnidx) ||
764         (filter->gridy <= filter->motioncellsidx[i].lineidx)) {
765       cellscnt++;
766     }
767   }
768   newcellscnt = filter->motioncells_count - cellscnt;
769   motioncellsidx = g_new0 (motioncellidx, newcellscnt);
770   for (i = 0; i < filter->motioncells_count; i++) {
771     if ((filter->motioncellsidx[i].lineidx < filter->gridy) &&
772         (filter->motioncellsidx[i].columnidx < filter->gridx)) {
773       motioncellsidx[j].lineidx = filter->motioncellsidx[i].lineidx;
774       motioncellsidx[j].columnidx = filter->motioncellsidx[i].columnidx;
775       j++;
776     }
777   }
778   GFREE (filter->motioncellsidx);
779   filter->motioncells_count = newcellscnt;
780   filter->motioncellsidx = g_new0 (motioncellidx, filter->motioncells_count);
781   j = 0;
782   for (i = 0; i < filter->motioncells_count; i++) {
783     filter->motioncellsidx[i].lineidx = motioncellsidx[j].lineidx;
784     filter->motioncellsidx[i].columnidx = motioncellsidx[j].columnidx;
785     j++;
786   }
787   GFREE (motioncellsidx);
788 }
789
790 static void
791 gst_motioncells_update_motion_masks (GstMotioncells * filter)
792 {
793
794   int i = 0;
795   int maskcnt = 0;
796   int j = 0;
797   int newmaskcnt;
798   motioncellidx *motionmaskcellsidx;
799   for (i = 0; i < filter->motionmaskcells_count; i++) {
800     if ((filter->gridx <= filter->motionmaskcellsidx[i].columnidx) ||
801         (filter->gridy <= filter->motionmaskcellsidx[i].lineidx)) {
802       maskcnt++;
803     }
804   }
805   newmaskcnt = filter->motionmaskcells_count - maskcnt;
806   motionmaskcellsidx = g_new0 (motioncellidx, newmaskcnt);
807   for (i = 0; i < filter->motionmaskcells_count; i++) {
808     if ((filter->motionmaskcellsidx[i].lineidx < filter->gridy) &&
809         (filter->motionmaskcellsidx[i].columnidx < filter->gridx)) {
810       motionmaskcellsidx[j].lineidx = filter->motionmaskcellsidx[i].lineidx;
811       motionmaskcellsidx[j].columnidx = filter->motionmaskcellsidx[i].columnidx;
812       j++;
813     }
814   }
815   GFREE (filter->motionmaskcellsidx);
816   filter->motionmaskcells_count = newmaskcnt;
817   filter->motionmaskcellsidx =
818       g_new0 (motioncellidx, filter->motionmaskcells_count);
819   j = 0;
820   for (i = 0; i < filter->motionmaskcells_count; i++) {
821     filter->motionmaskcellsidx[i].lineidx = motionmaskcellsidx[j].lineidx;
822     filter->motionmaskcellsidx[i].columnidx = motionmaskcellsidx[j].columnidx;
823     j++;
824   }
825   GFREE (motionmaskcellsidx);
826 }
827
828 /* GstElement vmethod implementations */
829
830 /* this function handles the link with other elements */
831 static gboolean
832 gst_motion_cells_set_caps (GstPad * pad, GstCaps * caps)
833 {
834   GstMotioncells *filter;
835   GstPad *otherpad;
836   GstStructure *structure;
837   int numerator, denominator;
838
839   filter = gst_motion_cells (gst_pad_get_parent (pad));
840   structure = gst_caps_get_structure (caps, 0);
841   gst_structure_get_int (structure, "width", &filter->width);
842   gst_structure_get_int (structure, "height", &filter->height);
843   gst_structure_get_fraction (structure, "framerate", &numerator, &denominator);
844   filter->framerate = (double) numerator / (double) denominator;
845   if (filter->cvImage)
846     cvReleaseImage (&filter->cvImage);
847   filter->cvImage =
848       cvCreateImage (cvSize (filter->width, filter->height), IPL_DEPTH_8U, 3);
849
850   otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad;
851   gst_object_unref (filter);
852
853   return gst_pad_set_caps (otherpad, caps);
854 }
855
856 /* chain function
857  * this function does the actual processing
858  */
859 static GstFlowReturn
860 gst_motion_cells_chain (GstPad * pad, GstBuffer * buf)
861 {
862
863   GstMotioncells *filter;
864
865   filter = gst_motion_cells (GST_OBJECT_PARENT (pad));
866   if (filter->calculate_motion) {
867     double sensitivity;
868     int framerate, gridx, gridy, motionmaskcells_count, motionmaskcoord_count,
869         motioncells_count, i;
870     int thickness, success, motioncellsidxcnt, numberOfCells,
871         motioncellsnumber, cellsOfInterestNumber;
872     int mincellsOfInterestNumber, motiondetect;
873     char *datafile;
874     bool display, changed_datafile, useAlpha;
875     gint64 starttime;
876     motionmaskcoordrect *motionmaskcoords;
877     motioncellidx *motionmaskcellsidx;
878     cellscolor motioncellscolor;
879     motioncellidx *motioncellsidx;
880     g_mutex_lock (filter->propset_mutex);
881     buf = gst_buffer_make_writable (buf);
882     filter->cvImage->imageData = (char *) GST_BUFFER_DATA (buf);
883     if (filter->firstframe) {
884       setPrevFrame (filter->cvImage, filter->id);
885       filter->firstframe = FALSE;
886     }
887
888     sensitivity = filter->sensitivity;
889     framerate = filter->framerate;
890     gridx = filter->gridx;
891     gridy = filter->gridy;
892     display = filter->display;
893     motionmaskcoord_count = filter->motionmaskcoord_count;
894     motionmaskcoords =
895         g_new0 (motionmaskcoordrect, filter->motionmaskcoord_count);
896     for (i = 0; i < filter->motionmaskcoord_count; i++) {       //we need divide 2 because we use gauss pyramid in C++ side
897       motionmaskcoords[i].upper_left_x =
898           filter->motionmaskcoords[i].upper_left_x / 2;
899       motionmaskcoords[i].upper_left_y =
900           filter->motionmaskcoords[i].upper_left_y / 2;
901       motionmaskcoords[i].lower_right_x =
902           filter->motionmaskcoords[i].lower_right_x / 2;
903       motionmaskcoords[i].lower_right_y =
904           filter->motionmaskcoords[i].lower_right_y / 2;
905     }
906
907     motioncellscolor.R_channel_value =
908         filter->motioncellscolor->R_channel_value;
909     motioncellscolor.G_channel_value =
910         filter->motioncellscolor->G_channel_value;
911     motioncellscolor.B_channel_value =
912         filter->motioncellscolor->B_channel_value;
913
914     if ((filter->changed_gridx || filter->changed_gridy
915             || filter->changed_startime)) {
916       if ((g_strcmp0 (filter->cur_datafile, NULL) != 0)) {
917         GFREE (filter->cur_datafile);
918         filter->datafileidx++;
919         filter->cur_datafile =
920             g_strdup_printf ("%s-%d.%s", filter->basename_datafile,
921             filter->datafileidx, filter->datafile_extension);
922         filter->changed_datafile = TRUE;
923         motion_cells_free_resources (filter->id);
924       }
925       if (filter->motioncells_count > 0)
926         gst_motioncells_update_motion_cells (filter);
927       if (filter->motionmaskcells_count > 0)
928         gst_motioncells_update_motion_masks (filter);
929       filter->changed_gridx = FALSE;
930       filter->changed_gridy = FALSE;
931       filter->changed_startime = FALSE;
932     }
933     datafile = g_strdup (filter->cur_datafile);
934     filter->cur_buff_timestamp = (GST_BUFFER_TIMESTAMP (buf) / GST_MSECOND);
935     filter->starttime +=
936         (filter->cur_buff_timestamp - filter->prev_buff_timestamp);
937     starttime = filter->starttime;
938     if (filter->changed_datafile || filter->diff_timestamp < 0)
939       filter->diff_timestamp =
940           (gint64) (GST_BUFFER_TIMESTAMP (buf) / GST_MSECOND);
941     changed_datafile = filter->changed_datafile;
942     motionmaskcells_count = filter->motionmaskcells_count;
943     motionmaskcellsidx = g_new0 (motioncellidx, filter->motionmaskcells_count);
944     for (i = 0; i < filter->motionmaskcells_count; i++) {
945       motionmaskcellsidx[i].lineidx = filter->motionmaskcellsidx[i].lineidx;
946       motionmaskcellsidx[i].columnidx = filter->motionmaskcellsidx[i].columnidx;
947     }
948     motioncells_count = filter->motioncells_count;
949     motioncellsidx = g_new0 (motioncellidx, filter->motioncells_count);
950     for (i = 0; i < filter->motioncells_count; i++) {
951       motioncellsidx[i].lineidx = filter->motioncellsidx[i].lineidx;
952       motioncellsidx[i].columnidx = filter->motioncellsidx[i].columnidx;
953     }
954     useAlpha = filter->usealpha;
955     thickness = filter->thickness;
956     success =
957         perform_detection_motion_cells (filter->cvImage, sensitivity, framerate,
958         gridx, gridy,
959         (gint64) (GST_BUFFER_TIMESTAMP (buf) / GST_MSECOND) -
960         filter->diff_timestamp, display, useAlpha, motionmaskcoord_count,
961         motionmaskcoords, motionmaskcells_count, motionmaskcellsidx,
962         motioncellscolor, motioncells_count, motioncellsidx, starttime,
963         datafile, changed_datafile, thickness, filter->id);
964     if ((success == 1) && (filter->sent_init_error_msg == false)) {
965       char *initfailedreason;
966       int initerrorcode;
967       GstStructure *s;
968       GstMessage *m;
969       initfailedreason = getInitDataFileFailed (filter->id);
970       initerrorcode = getInitErrorCode (filter->id);
971       s = gst_structure_new ("motion", "init_error_code", G_TYPE_INT,
972           initerrorcode, "details", G_TYPE_STRING, initfailedreason, NULL);
973       m = gst_message_new_element (GST_OBJECT (filter), s);
974       gst_element_post_message (GST_ELEMENT (filter), m);
975       filter->sent_init_error_msg = TRUE;
976     }
977     if ((success == -1) && (filter->sent_save_error_msg == false)) {
978       char *savefailedreason;
979       int saveerrorcode;
980       GstStructure *s;
981       GstMessage *m;
982       savefailedreason = getSaveDataFileFailed (filter->id);
983       saveerrorcode = getSaveErrorCode (filter->id);
984       s = gst_structure_new ("motion", "save_error_code", G_TYPE_INT,
985           saveerrorcode, "details", G_TYPE_STRING, savefailedreason, NULL);
986       m = gst_message_new_element (GST_OBJECT (filter), s);
987       gst_element_post_message (GST_ELEMENT (filter), m);
988       filter->sent_save_error_msg = TRUE;
989     }
990     if (success == -2) {        //frame dropped
991       filter->prev_buff_timestamp = filter->cur_buff_timestamp;
992       //free
993       GFREE (datafile);
994       GFREE (motionmaskcoords);
995       GFREE (motionmaskcellsidx);
996       GFREE (motioncellsidx);
997       g_mutex_unlock (filter->propset_mutex);
998       return gst_pad_push (filter->srcpad, buf);
999     }
1000     filter->changed_datafile = getChangedDataFile (filter->id);
1001     motioncellsidxcnt = getMotionCellsIdxCnt (filter->id);
1002     numberOfCells = filter->gridx * filter->gridy;
1003     motioncellsnumber = motioncellsidxcnt / MSGLEN;
1004     cellsOfInterestNumber = (filter->motioncells_count > 0) ?   //how many cells interest for us
1005         (filter->motioncells_count) : (numberOfCells);
1006     mincellsOfInterestNumber =
1007         floor ((double) cellsOfInterestNumber * filter->threshold);
1008     motiondetect = (motioncellsnumber >= mincellsOfInterestNumber) ? 1 : 0;
1009     if ((motioncellsidxcnt > 0) && (motiondetect == 1)) {
1010       char *detectedmotioncells;
1011       filter->last_motion_timestamp = GST_BUFFER_TIMESTAMP (buf);
1012       detectedmotioncells = getMotionCellsIdx (filter->id);
1013       if (detectedmotioncells) {
1014         filter->consecutive_motion++;
1015         if ((filter->previous_motion == false)
1016             && (filter->consecutive_motion >= filter->minimum_motion_frames)) {
1017           GstStructure *s;
1018           GstMessage *m;
1019           filter->previous_motion = true;
1020           filter->motion_begin_timestamp = GST_BUFFER_TIMESTAMP (buf);
1021           s = gst_structure_new ("motion", "motion_cells_indices",
1022               G_TYPE_STRING, detectedmotioncells, "motion_begin", G_TYPE_UINT64,
1023               filter->motion_begin_timestamp, NULL);
1024           m = gst_message_new_element (GST_OBJECT (filter), s);
1025           gst_element_post_message (GST_ELEMENT (filter), m);
1026         } else if (filter->postallmotion) {
1027           GstStructure *s;
1028           GstMessage *m;
1029           filter->motion_timestamp = GST_BUFFER_TIMESTAMP (buf);
1030           s = gst_structure_new ("motion", "motion_cells_indices",
1031               G_TYPE_STRING, detectedmotioncells, "motion", G_TYPE_UINT64,
1032               filter->motion_timestamp, NULL);
1033           m = gst_message_new_element (GST_OBJECT (filter), s);
1034           gst_element_post_message (GST_ELEMENT (filter), m);
1035         }
1036       } else {
1037         GstStructure *s;
1038         GstMessage *m;
1039         s = gst_structure_new ("motion", "motion_cells_indices", G_TYPE_STRING,
1040             "error", NULL);
1041         m = gst_message_new_element (GST_OBJECT (filter), s);
1042         gst_element_post_message (GST_ELEMENT (filter), m);
1043       }
1044     } else {
1045       filter->consecutive_motion = 0;
1046       if ((((GST_BUFFER_TIMESTAMP (buf) -
1047                       filter->last_motion_timestamp) / 1000000000l) >=
1048               filter->gap)
1049           && (filter->last_motion_timestamp > 0)) {
1050         GST_DEBUG ("POST MOTION FINISHED MSG\n");
1051         if (filter->previous_motion) {
1052           GstStructure *s;
1053           GstMessage *m;
1054           filter->previous_motion = false;
1055           s = gst_structure_new ("motion", "motion_finished", G_TYPE_UINT64,
1056               filter->last_motion_timestamp, NULL);
1057           m = gst_message_new_element (GST_OBJECT (filter), s);
1058           gst_element_post_message (GST_ELEMENT (filter), m);
1059         }
1060       }
1061     }
1062     if (filter->postnomotion > 0) {
1063       guint64 last_buf_timestamp = GST_BUFFER_TIMESTAMP (buf) / 1000000000l;
1064       if ((last_buf_timestamp -
1065               (filter->last_motion_timestamp / 1000000000l)) >=
1066           filter->postnomotion) {
1067         GST_DEBUG ("POST NO MOTION MSG\n");
1068         if ((last_buf_timestamp -
1069                 (filter->last_nomotion_notified / 1000000000l)) >=
1070             filter->postnomotion) {
1071           GstStructure *s;
1072           GstMessage *m;
1073           filter->last_nomotion_notified = GST_BUFFER_TIMESTAMP (buf);
1074           s = gst_structure_new ("motion", "no_motion", G_TYPE_UINT64,
1075               filter->last_motion_timestamp, NULL);
1076           m = gst_message_new_element (GST_OBJECT (filter), s);
1077           gst_element_post_message (GST_ELEMENT (filter), m);
1078         }
1079       }
1080     }
1081     filter->prev_buff_timestamp = filter->cur_buff_timestamp;
1082     //free
1083     GFREE (datafile);
1084     GFREE (motionmaskcoords);
1085     GFREE (motionmaskcellsidx);
1086     GFREE (motioncellsidx);
1087
1088     g_mutex_unlock (filter->propset_mutex);
1089   }
1090
1091   return gst_pad_push (filter->srcpad, buf);
1092 }
1093
1094 /* entry point to initialize the plug-in
1095  * initialize the plug-in itself
1096  * register the element factories and other features
1097  */
1098 gboolean
1099 gst_motioncells_plugin_init (GstPlugin * plugin)
1100 {
1101   /* debug category for fltering log messages */
1102   GST_DEBUG_CATEGORY_INIT (gst_motion_cells_debug,
1103       "motioncells",
1104       0,
1105       "Performs motion detection on videos, providing detected positions via bus messages");
1106
1107   return gst_element_register (plugin, "motioncells", GST_RANK_NONE,
1108       GST_TYPE_MOTIONCELLS);
1109 }