From acd39fe15bae3f5451b80e453f0307de8c5aa8a7 Mon Sep 17 00:00:00 2001
From: basos G <noxelia 4t gmail , com>
Date: Wed, 20 Aug 2008 09:52:19 +0300
Subject: [PATCH] Add:: Static Detect Video FIlter

Static detect detects stationary images within a video and takes snapshots of them.
It is fully parametrized to account for videos with different amount of irrelevant motion
(e.g. noise). Main parameters are motion tolerance and stationary time. The module is
called static. Full parameter description with vlc -p static --advanced.
We also support sensivity parameter callback for realtime update and a custom snapshot
command for manual operation to overcome motion meter being snapshoted
Rev 2
---
 configure.ac                         |    3 +-
 modules/video_filter/Modules.am      |    1 +
 modules/video_filter/beep.c          |  141 ++++++
 modules/video_filter/beep.h          |   15 +
 modules/video_filter/static_detect.c |  865 ++++++++++++++++++++++++++++++++++
 5 files changed, 1024 insertions(+), 1 deletions(-)
 create mode 100644 modules/video_filter/beep.c
 create mode 100644 modules/video_filter/beep.h
 create mode 100644 modules/video_filter/static_detect.c

diff --git a/configure.ac b/configure.ac
index 0eec721..b2df413 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ VERSION_REVISION="0"
 VERSION_EXTRA="-git"
 
 CONFIGURE_LINE="`echo "$0 $ac_configure_args" | sed -e 's/\\\/\\\\\\\/g'`"
-CODENAME="Goldeneye"
+CODENAME="Mefisto"
 COPYRIGHT_YEARS="1996-2008"
 
 AC_PREREQ(2.59c)
@@ -1101,6 +1101,7 @@ VLC_ADD_PLUGIN([ripple])
 VLC_ADD_PLUGIN([psychedelic])
 VLC_ADD_PLUGIN([gradient])
 VLC_ADD_PLUGIN([motionblur])
+VLC_ADD_PLUGIN([staticdetect])
 VLC_ADD_PLUGIN([rv32])
 VLC_ADD_PLUGIN([rotate])
 VLC_ADD_PLUGIN([noise])
diff --git a/modules/video_filter/Modules.am b/modules/video_filter/Modules.am
index 02bad05..13a5e5d 100644
--- a/modules/video_filter/Modules.am
+++ b/modules/video_filter/Modules.am
@@ -15,6 +15,7 @@ SOURCES_marq = marq.c
 SOURCES_rss = rss.c
 SOURCES_motiondetect = motiondetect.c
 SOURCES_rv32 = rv32.c
+SOURCES_staticdetect = static_detect.c beep.c
 SOURCES_osdmenu = osdmenu.c
 SOURCES_remoteosd = remoteosd.c remoteosd_rfbproto.h
 SOURCES_magnify = magnify.c
diff --git a/modules/video_filter/beep.c b/modules/video_filter/beep.c
new file mode 100644
index 0000000..6d2d5bc
--- /dev/null
+++ b/modules/video_filter/beep.c
@@ -0,0 +1,141 @@
+/* A Beep facility implemented on windows and linux */
+#include "beep.h"
+
+#ifdef __linux__
+/*  beep - just what it sounds like, makes the console beep - but with
+ * precision control.  See the man page for details.
+ *
+ *
+ * This code is copyright (C) Johnathan Nightingale, 2000.
+ *
+ * This code may distributed only under the terms of the GNU Public License
+ * which can be found at http://www.gnu.org/copyleft or in the file COPYING
+ * supplied with this code.
+ *
+ * This code is not distributed with warranties of any kind, including implied
+ * warranties of merchantability or fitness for a particular use or ability to
+ * breed pandas in captivity, it just can't be done.
+ *
+ * Bug me, I like it:  http://johnath.com/  or johnath@johnath.com
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/kd.h>
+
+/* I don't know where this number comes from, I admit that freely.  A
+   wonderful human named Raine M. Ekman used it in a program that played
+   a tune at the console, and apparently, it's how the kernel likes its
+   sound requests to be phrased.  If you see Raine, thank him for me.
+
+   June 28, email from Peter Tirsek (peter at tirsek dot com):
+
+   This number represents the fixed frequency of the original PC XT's
+   timer chip (the 8254 AFAIR), which is approximately 1.193 MHz. This
+   number is divided with the desired frequency to obtain a counter value,
+   that is subsequently fed into the timer chip, tied to the PC speaker.
+   The chip decreases this counter at every tick (1.193 MHz) and when it
+   reaches zero, it toggles the state of the speaker (on/off, or in/out),
+   resets the counter to the original value, and starts over. The end
+   result of this is a tone at approximately the desired frequency. :)
+*/
+#ifndef CLOCK_TICK_RATE
+#define CLOCK_TICK_RATE 1193180
+#endif
+
+#define VERSION_STRING "beep-1.2.2"
+
+/* Meaningful Defaults */
+
+#define DEFAULT_REPS       1
+#define DEFAULT_DELAY      100   /* milliseconds */
+
+
+typedef struct beep_parms_t {
+  float freq;     /* tone frequency (Hz)      */
+  int length;     /* tone length    (ms)      */
+  int reps;       /* # of repetitions         */
+  int delay;      /* delay between reps  (ms) */
+} beep_parms_t;
+
+int play_beep(float freq, int length) {
+
+  int i; /* loop counter */
+  int console_fd; /* file descriptor */
+  beep_parms_t parms;
+
+  /* try to snag the console */
+  if((console_fd = open("/dev/console", O_WRONLY)) == -1) {
+    //fprintf(stderr, "Could not open /dev/console for writing.\n");
+    printf("\a");  /* Output the only beep we can, in an effort to fall back on usefulness */
+    return -1;
+  }
+
+  parms.freq       = ( freq ? freq : DEFAULT_FREQ );
+  parms.length     = ( length ? length : DEFAULT_LENGTH );
+  parms.reps       = DEFAULT_REPS;
+  parms.delay      = DEFAULT_DELAY;
+
+  /* Beep */
+  for (i = 0; i < parms.reps; i++) {                    /* start beep */
+    if(ioctl(console_fd, KIOCSOUND, (int)(CLOCK_TICK_RATE/parms.freq)) < 0) {
+      printf("\a");  /* Output the only beep we can, in an effort to fall back on usefulness */
+      return -2;
+    }
+    /* Look ma, I'm not ansi C compatible! */
+    usleep(1000*parms.length);                          /* wait...    */
+    ioctl(console_fd, KIOCSOUND, 0);                    /* stop beep  */
+    if(i+1 < parms.reps)
+       usleep(1000*parms.delay);                        /* wait...    */
+  }
+  close(console_fd);
+  return 0;
+}
+
+/* If we get interrupted, it would be nice to not leave the speaker beeping in
+   perpetuity. */
+/*void handle_signal(int signum) {
+  switch(signum) {
+  case SIGINT:
+    if(console_fd >= 0) {
+      // Kill the sound, quit gracefully
+      ioctl(console_fd, KIOCSOUND, 0);
+      close(console_fd);
+      exit(signum);
+    } else {
+      // Just quit gracefully
+      exit(signum);
+    }
+  }
+}*/
+
+
+#elif defined WIN32
+
+#include <windows.h>
+int play_beep( float freq, int length)
+{
+    int freqi = (int) freq;
+    if ( !freq ) freq = DEFAULT_FREQ;
+    if ( !length ) length = DEFAULT_LENGTH;
+    if ( freqi > 32767 || freqi < 37 )
+        return -10;
+    if ( Beep( freqi, length ) ) /* error occured */
+         return -11;
+    return 0;
+}
+
+#else
+/* Other Platforms should be quiet for now... */
+int play_beep( float freq, int length)
+{
+    return -40;
+}
+#endif
diff --git a/modules/video_filter/beep.h b/modules/video_filter/beep.h
new file mode 100644
index 0000000..e26cae5
--- /dev/null
+++ b/modules/video_filter/beep.h
@@ -0,0 +1,15 @@
+/* A Beep facility implemented on windows and linux */
+/* Prototype : we export a windows/linux beep function
+   arg1 frequency in Hz (notice that in windows the range is 37 to 32767 Hz)
+   arg2 beep duration in miliseconds
+   Return Value : 0 = success
+                  < 0 = error
+   Also note that in linux if we get interrupted by signal and the program exits
+      the console may still beeping
+
+   moded by basOS 2008
+*/
+int play_beep(float freq, int length);
+
+#define DEFAULT_FREQ       440.0 /* Middle A */
+#define DEFAULT_LENGTH     200   /* milliseconds */
diff --git a/modules/video_filter/static_detect.c b/modules/video_filter/static_detect.c
new file mode 100644
index 0000000..3937b7e
--- /dev/null
+++ b/modules/video_filter/static_detect.c
@@ -0,0 +1,865 @@
+/*****************************************************************************
+ * motion_blur.c : static detect filter for VLC
+ *****************************************************************************
+ * Copyright (C) 2008 the VideoLAN team
+ *
+ * Authors: basOS G <noxelia 4t gmai1 , c0m>
+ *  based on the work of Antoine Cellerier for motion detect VLC VFilter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout.h>
+#include <vlc_filter.h>
+#include "filter_picture.h"
+#include "beep.h"
+#include <assert.h>
+/*#include <vlc/vlc.h>
+#include <vlc/libvlc_internal.h>
+*/
+
+/*****************************************************************************
+ * Help Data Types
+ *****************************************************************************/
+#undef NOIZ  /* Should we compile a noise reduction filter ? Leave it out for now w*/
+/*difference frame data type: 16 bit for now to account for overflow (8 bit per channel
+  x 3 channels: max diff is 256x3 = 768 : we need more than 8 bits */
+typedef uint16_t diff_t;
+typedef void ( *findDiffs_t )( diff_t*, picture_t*, picture_t*, filter_t *  );
+typedef void ( *motionMeter_t )( float , float , picture_t* , filter_t*  );
+/*typedef void ( *markPicture_t )( diff_t*, picture_t*, diff_t , filter_t * p_filter );*/
+
+/*****************************************************************************
+ * Local protypes
+ *****************************************************************************/
+static int  Create       ( vlc_object_t * );
+static void Destroy      ( vlc_object_t * );
+static picture_t *Filter ( filter_t *, picture_t * );
+
+/*****************************************************************************
+ ** Some Predefined Protos
+ *****************************************************************************/
+void findDiffs (diff_t* p_diff, picture_t* p_new_pic, picture_t* p_old_pic, filter_t * p_filter );
+void findDiffsPacked (diff_t* p_diff, picture_t* p_new_pic, picture_t* p_old_pic, filter_t * p_filter);
+#ifdef NOIZ
+static void GaussianConvolution( diff_t *p_inpix, picture_t* p_ref_pic );
+#endif
+float countMovedPixelsPercent( diff_t* p_diff, picture_t* p_ref_pic, diff_t i_motion_threshold );
+void motionMeter( float f_motion, float f_threshold, picture_t* p_out_pic, filter_t* p_filter );
+void motionMeterPacked( float f_motion, float f_threshold, picture_t* p_out_pic, filter_t* p_filter );
+
+/*void markPicture( diff_t* p_diff, picture_t* p_out_pic, diff_t , filter_t * p_filter );
+void markPicturePacked( diff_t* p_diff, picture_t* p_out_pic, diff_t , filter_t * p_filter ); */
+static int StaticDetectCallback( vlc_object_t *, char const *,
+                               vlc_value_t, vlc_value_t, void * );
+static void resetStats( filter_t* p_filter );
+static void echoStats( filter_t* p_filter );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+#define MTHRESHOLD_TEXT N_("Motion Tolerance Percent")
+#define MTHRESHOLD_LONGTEXT N_("Percentage of image pixels that have to be changed for motion to be detected.")
+#define TTHRESHOLD_TEXT N_("Static Time needed for snapshot (mseconds)")
+#define TTHRESHOLD_LONGTEXT N_("Amount of time in mseconds that video should remain unchanged for a snapshot to occur.")
+#define DTHRESHOLD_TEXT N_("Motion Sensivity Percent")
+#define DTHRESHOLD_LONGTEXT N_("Changes the amount of chroma and luminance difference for two pixels to be considered changed. You should mess with Motion Tolerance first if you want to tune motion detection system sensivity.")
+#define FREEZE_TEXT N_("Snapshot Freeze Time (mseconds)")
+#define FREEZE_LONGTEXT N_("How long should the snapped image stay freezed on the video. Use 0 to disable")
+#define MOTIONM_TEXT N_("Display Motion meter")
+#define BEEP_TEXT N_("Beep When Static Detected")
+
+#define FILTER_PREFIX "staticdetect-"
+#define PAR_MTHRESHOLD "tolerance"
+#define PAR_TTHRESHOLD "snaptime"
+#define PAR_DTHRESHOLD "sensivity"
+#define PAR_FREEZETIME "freezetime"
+#define PAR_MMETER "motionmeter"
+#define PAR_BEEP "beep"
+#define PAR_TAKESNAPSHOT "takesnapshot"
+
+/* default difference threshold */
+#define DEFAULT_DIFF_THRESHOLD 98.8
+/* PIX DIFF MAX IS 3*2^8 for 8 bit YCbCr components */
+#define MAX_ABSOLUTE_PIX_DIFF 3*255
+/* default time threshold */
+#define DEFAULT_TIME_THRESHOLD 700
+/* default pix count percent threshold */
+#define DEFAULT_PIX_COUNT_THRESHOLD 1.1
+/*default motion meter stat */
+#define DEFAULT_MMETER true
+/* time the station mark should be presented (in msecs)*/
+#define DEFAULT_FREEZE_TIME 1200
+/* default beep status */
+#define DEFAULT_BEEP true
+
+vlc_module_begin();
+    set_shortname( N_("Static Image Detector") );
+    set_description( N_("Detects stationary images from a video and takes snapshots of them") );
+    set_capability( "video filter2", 0 );
+    set_category( CAT_VIDEO );
+    set_subcategory( SUBCAT_VIDEO_VFILTER );
+
+    add_float_with_range( FILTER_PREFIX PAR_MTHRESHOLD, DEFAULT_PIX_COUNT_THRESHOLD, 1, 100, NULL,
+                        MTHRESHOLD_TEXT, MTHRESHOLD_LONGTEXT, false );
+    add_integer ( FILTER_PREFIX PAR_TTHRESHOLD, DEFAULT_TIME_THRESHOLD, NULL,
+                        TTHRESHOLD_TEXT, TTHRESHOLD_LONGTEXT, false );
+    add_integer ( FILTER_PREFIX PAR_FREEZETIME, DEFAULT_FREEZE_TIME, NULL,
+                        FREEZE_TEXT, FREEZE_LONGTEXT, true );
+    add_float_with_range ( FILTER_PREFIX PAR_DTHRESHOLD, DEFAULT_DIFF_THRESHOLD, 0, 100, NULL,
+			DTHRESHOLD_TEXT, DTHRESHOLD_LONGTEXT, false );
+    add_bool ( FILTER_PREFIX PAR_MMETER, DEFAULT_MMETER, NULL,
+                        MOTIONM_TEXT, NULL, false );
+    add_bool ( FILTER_PREFIX PAR_BEEP, DEFAULT_BEEP, NULL,
+			BEEP_TEXT, NULL, true );
+    add_shortcut( "static" );
+
+    set_callbacks( Create, Destroy );
+vlc_module_end();
+
+/*TOCHECK : WHAT is this for?? It parses command line args without it*/
+static const char *const psz_filter_options[] = {
+    PAR_MTHRESHOLD,
+    PAR_TTHRESHOLD,
+    PAR_DTHRESHOLD,
+    PAR_FREEZETIME,
+    PAR_MMETER,
+    PAR_BEEP,
+     NULL
+};
+
+
+/*****************************************************************************
+ * filter_sys_t
+ *****************************************************************************/
+struct filter_sys_t
+{
+    findDiffs_t pf_findDiffs ; /* findPixelDiffs: are we on a packed YCbCr data format? see www.fourcc.org */
+    /*markPicture_t pf_markPicture;*/ /* mark Pixel Diffs */
+    motionMeter_t pf_motionMeter; /* Draw a nice motion meter */
+
+    float f_pix_count_thres_percent ; /* motion threshold % pixels of an image */
+    int i_frame_thres ; /* time threshold of stationary image at msecs */
+    diff_t i_pix_diff_thres ;/* Difference of 2 pixels to mark it as changed */
+
+    bool b_is_snaped ; /* Is the picture snaped */
+    int i_static_frames ; /* # of static frames */
+    bool b_beep ; /* Should we beep ? */
+
+    picture_t* p_old_pic; /*previous frame */
+    bool b_has_old_pic;
+    diff_t* p_diff; /*difference frame */
+
+    picture_t* p_freeze_pic; /*difference frame for marking video output */
+    int i_freeze_frames; /* # of frames used for marking */
+    int i_freeze_counter; /* # of frames left to dispay the current differencies*/
+
+    /* various motion stats */
+    float f_motion_min;
+    float f_motion_max;
+    unsigned int i_motion_n;
+    float f_motion_avg;
+};
+
+/* Motion Statistics Handling */
+void resetStats( filter_t* p_filter )
+{
+    p_filter->p_sys->i_motion_n = 0;
+    p_filter->p_sys->f_motion_max = 0 ;
+    p_filter->p_sys->f_motion_min = 100 ;
+    p_filter->p_sys->f_motion_avg = 0 ;
+}
+void echoStats( filter_t* p_filter )
+{
+    msg_Dbg( p_filter, "Motion Stats:\n"
+             "[static]\tMinimum: %.4f\t Maximum: %.4f\tAverage: %.4f\tFrames:%d",
+             p_filter->p_sys->f_motion_min, p_filter->p_sys->f_motion_max,
+             p_filter->p_sys->f_motion_avg, p_filter->p_sys->i_motion_n );
+}
+
+/*****************************************************************************
+ ** Create
+ *****************************************************************************/
+static int Create( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t *)p_this;
+    const video_format_t *p_fmt = &p_filter->fmt_in.video;
+    findDiffs_t pf_findDiffs;
+    //markPicture_t pf_markPicture;
+    motionMeter_t pf_motionMeter;
+    filter_sys_t *p_sys;
+
+    switch( p_fmt->i_chroma )
+    {
+        CASE_PLANAR_YUV
+            pf_findDiffs = findDiffs;
+            //pf_markPicture = markPicture;
+            pf_motionMeter = motionMeter;
+            msg_Dbg( p_filter, "Using YUV *Planar* Chroma") ;
+            break;
+
+        CASE_PACKED_YUV_422
+            pf_findDiffs = findDiffsPacked ;
+            //pf_markPicture = markPicturePacked ;
+            pf_motionMeter = motionMeterPacked ;
+            msg_Dbg( p_filter, "Using YUV *Packed* Chroma") ;
+            break;
+
+        default:
+            msg_Err( p_filter, "Unsupported input chroma (%4s)",
+                     (char*)&(p_fmt->i_chroma) );
+            return VLC_EGENERIC;
+    }
+
+    /* Allocate structure */
+    p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) );
+    if( p_sys == NULL )
+        return VLC_ENOMEM;
+
+
+    /* Parse config */
+    config_ChainParse( p_filter, FILTER_PREFIX, psz_filter_options,
+                       p_filter->p_cfg );
+
+    /* Initialize parameters */
+    p_sys->f_pix_count_thres_percent =
+        var_CreateGetFloat( p_filter, FILTER_PREFIX PAR_MTHRESHOLD );
+
+    int i_time_threshold =
+        var_CreateGetInteger( p_filter, FILTER_PREFIX PAR_TTHRESHOLD );
+    float f_frame_rate ;
+    switch ( p_fmt->i_frame_rate_base )
+    { /* NASTY hack to deal with nasty frame rate values in various formats ... */
+        case 0 :
+            f_frame_rate = 25 ;
+        break;
+        case 1 :
+            f_frame_rate = ( (float) p_fmt->i_frame_rate / ( p_fmt->i_frame_rate > 1000 ? 1000 : 1 ) ) ;
+        break;
+        default :
+            f_frame_rate = ( (float) p_fmt->i_frame_rate / p_fmt->i_frame_rate_base ) ;
+    }
+    p_sys->i_frame_thres = ((float) i_time_threshold / 1000) * ( f_frame_rate ) ;
+
+    int i_freeze_time =
+        var_CreateGetInteger( p_filter, FILTER_PREFIX PAR_FREEZETIME );
+    msg_Dbg( p_filter, "frame rate=%d  base=%d:\n", p_fmt->i_frame_rate , p_fmt->i_frame_rate_base );
+    p_sys->i_freeze_frames =  ((float) i_freeze_time / 1000) * ( f_frame_rate ) ;
+
+    float f_pixsens_pcnt =
+        var_CreateGetFloatCommand( p_filter, FILTER_PREFIX PAR_DTHRESHOLD );
+    p_filter->p_sys->i_pix_diff_thres =  ( 100 - f_pixsens_pcnt ) * MAX_ABSOLUTE_PIX_DIFF / 100 ;
+    var_AddCallback( p_filter, FILTER_PREFIX PAR_DTHRESHOLD,
+                     StaticDetectCallback, p_filter );
+
+    bool b_meter = var_CreateGetBool( p_filter, FILTER_PREFIX PAR_MMETER );
+    if ( !b_meter)  pf_motionMeter = NULL;
+
+    p_sys->b_beep = var_CreateGetBool( p_filter, FILTER_PREFIX PAR_BEEP );
+
+	/* Custom snapshot to overcome motion meter being snapshoted from a
+		normal libvlc snapshot call */
+	var_Create( p_filter, FILTER_PREFIX PAR_TAKESNAPSHOT, VLC_VAR_BOOL | VLC_VAR_ISCOMMAND );
+	var_AddCallback( p_filter, FILTER_PREFIX PAR_TAKESNAPSHOT,
+						StaticDetectCallback, p_filter ) ;
+
+    msg_Dbg( p_filter, "Static Detect Parameters:\n"
+                       "\t[static] Pixel Count Threshold= %.2f\n"
+                       "\t[static] Frame Count Threshold= %d\n"
+                       "\t[static] Pixel Difference Threshold= %d\n"
+                       "\t[static] Motion Meter %s\n",
+                       p_filter->p_sys->f_pix_count_thres_percent,
+                       p_filter->p_sys->i_frame_thres, p_filter->p_sys->i_pix_diff_thres,
+                       ( b_meter ? "on" : "off" ) );
+
+    p_sys->p_old_pic = picture_New( p_fmt->i_chroma,
+                                p_fmt->i_width, p_fmt->i_height, 0 );
+    p_sys->p_freeze_pic = picture_New( p_fmt->i_chroma,
+                                p_fmt->i_width, p_fmt->i_height, 0 );
+
+    p_sys->p_diff  = calloc( p_fmt->i_width * p_fmt->i_height, sizeof(*p_sys->p_diff) );
+
+    if( !p_sys->p_old_pic || !p_sys->p_diff || !p_sys->p_freeze_pic )
+    {
+        free( p_sys->p_diff );
+        if( p_sys->p_old_pic )
+            picture_Release( p_sys->p_old_pic );
+        if( p_sys->p_freeze_pic )
+            picture_Release( p_sys->p_freeze_pic );
+        return VLC_ENOMEM;
+    }
+
+    p_sys->b_has_old_pic = false;
+    p_sys->i_freeze_counter = 0;
+
+    resetStats( p_filter );
+
+    /* libvlc event manager */
+    /*libvlc_exception_t e;
+    libvlc_exception_init( &e );
+    p_filter->p_event_manager = libvlc_event_manager_new( p_filter, p_filter->p_libvlc_instance, &e );
+    libvlc_event_manager_register_event_type( p_fitler->p_event_manager, libvlc_snapshotTaken, &e );'
+    */
+
+   /* Set Video Filter Proccessor */
+    p_filter->pf_video_filter = Filter;
+    p_sys->pf_findDiffs = pf_findDiffs ;
+    //p_sys->pf_markPicture = pf_markPicture ;
+    p_sys->pf_motionMeter = pf_motionMeter ;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ ** Destroy
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t *)p_this;
+
+    echoStats( p_filter );
+    free( p_filter->p_sys->p_diff );
+    picture_Release( p_filter->p_sys->p_freeze_pic );
+    picture_Release( p_filter->p_sys->p_old_pic );
+    free( p_filter->p_sys );
+}
+
+
+/*****************************************************************************
+ * Filter
+ *****************************************************************************/
+static picture_t *Filter( filter_t *p_filter, picture_t *p_in_pic )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    picture_t *p_out_pic;
+    diff_t *p_diff = p_sys->p_diff;
+
+    if( !p_in_pic ) /* we are called with empty pic */
+        return NULL;
+
+
+    if( !p_sys->b_has_old_pic )
+    {   /* It is the first time we are called */
+        picture_Copy( p_sys->p_old_pic, p_in_pic );
+        p_sys->i_static_frames = 0;
+        p_sys->b_is_snaped = false ;
+		p_sys->b_has_old_pic = true;
+        return p_in_pic;
+    }
+    p_out_pic = filter_NewPicture( p_filter );
+
+    if( !p_out_pic )
+    {
+        picture_Release( p_in_pic );
+        return NULL;
+    }
+
+#if 1
+    /* Find Differences */
+    (p_sys->pf_findDiffs) ( p_diff, p_in_pic, p_sys->p_old_pic, p_filter );
+
+#ifdef NOIZ
+    /* Clean Diff Image from noise */
+    GaussianConvolution( p_diff, p_in_pic );
+#endif
+
+    /* Count moved pixels */
+    float f_motion ;
+    if ( (f_motion = countMovedPixelsPercent (p_diff, p_in_pic, p_sys->i_pix_diff_thres) )
+            > p_sys->f_pix_count_thres_percent )
+    { /* we have motion: reset static state */
+        //msg_Dbg( p_filter, "Motion Detected. Reseting state" );
+        p_sys->i_static_frames = 0;
+        p_sys->b_is_snaped = false;
+        //(p_sys->pf_markPicture) ( p_sys->p_diff, p_out_pic, p_sys->i_pix_diff_thres, p_filter );
+    } else /* we have static */
+    {
+        p_sys->i_static_frames++;
+        if ( p_sys->i_static_frames >= p_sys->i_frame_thres )
+        { /* we are too long stationary : snap it if not alredy */
+             if ( !p_sys->b_is_snaped ) {
+                  int ec;
+                  msg_Dbg( p_filter, "Static Detected. Snapping NOW" );
+                  if ( ( p_sys->i_freeze_counter = p_sys->i_freeze_frames ) )
+                      picture_Copy( p_sys->p_freeze_pic, p_in_pic );
+                  /* Keep the input width/height */
+                  var_SetInteger( (vout_thread_t*) p_filter->p_owner, "snapshot-width", 0 );
+                  var_SetInteger( (vout_thread_t*) p_filter->p_owner, "snapshot-height", 0 );
+                  vout_Snapshot( (vout_thread_t*) p_filter->p_owner, p_in_pic );
+                  /*vout_Control( (vout_thread_t*) p_filter->p_owner, VOUT_SNAPSHOT );*/
+                  if ( p_sys->b_beep )
+                       if ( (ec = play_beep ( 0, 0)) ) //play a default beep sound on the speaker
+                            msg_Warn( p_filter, "Error [%d] while Beeping",ec );
+                  p_sys->b_is_snaped = true;
+             }
+ #if 0
+             if ( p_sys->i_static_frames % 30 == 0 )
+                  msg_Dbg( p_filter, "Static Detected [%d]. %s", p_sys->i_static_frames,
+                 ( p_sys->b_is_snaped ? "Snapped" : "Not snapped" ) );
+#endif
+        }
+    }
+    if ( p_sys->i_motion_n % ( p_sys->i_frame_thres * 8 ) == 0 )
+    { /* echo stats every 8 times the static framecount */
+         echoStats( p_filter );
+         resetStats( p_filter );
+    }
+    /*update motion stats */
+    p_sys->f_motion_max = __MAX( p_sys->f_motion_max, f_motion );
+    p_sys->f_motion_min = __MIN( p_sys->f_motion_min, f_motion );
+    p_sys->f_motion_avg = ( p_sys->f_motion_avg * p_sys->i_motion_n + f_motion ) / ( ++p_sys->i_motion_n );
+
+    if ( p_sys->i_freeze_counter > 0 )
+    {
+        picture_Copy( p_out_pic, p_sys->p_freeze_pic );  /* Display the snapshot image for a while */
+        p_sys->i_freeze_counter-- ;
+    }
+    else
+        picture_Copy( p_out_pic, p_in_pic ); /* Just Copy the image data for display */
+
+    if (p_sys->pf_motionMeter)
+         ( p_sys->pf_motionMeter)( f_motion, p_sys->f_pix_count_thres_percent, p_out_pic, p_filter );
+#endif
+    /*
+     * We're done. Lets keep a copy of the picture
+     * TODO we may just picture_Release with a latency of 1 if the filters/vout
+     * handle it correctly */
+    picture_Copy( p_sys->p_old_pic, p_in_pic );
+
+    picture_Release( p_in_pic );
+    return p_out_pic;
+}
+
+void motionMeter( float f_motion, float f_threshold, picture_t* p_out_pic, filter_t* p_filter )
+{
+	VLC_UNUSED(p_filter);
+    /* Create a horizontial bar at the bottom of the picture showing the motion level */
+    const video_frame_format_t *p_fmt = &p_out_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    uint8_t* p_y_pix = p_out_pic->p[Y_PLANE].p_pixels;
+    const int i_y_pitch = p_out_pic->p[Y_PLANE].i_pitch;
+
+    unsigned int x,y;
+
+    #define HMARGIN  0.020  /* bar margin from left/right */
+    #define VMARGIN  0.010  /* bar margin from bottom */
+    #define BHEIGHT 0.025  /* bar height */
+    unsigned int i_bar_x1 = (float) i_width * HMARGIN ;
+    unsigned int i_bar_width = (float) i_width * ( 1 - 2 * HMARGIN ) ;
+    unsigned int i_bar_x2 = i_bar_x1 + i_bar_width ;
+    unsigned int i_bar_height = (float) i_height * ( BHEIGHT );
+    unsigned int i_bar_y1 = i_height - ( (float) i_height * VMARGIN + i_bar_height ) ;
+    unsigned int i_bar_y2 = i_height - ( (float) i_height * VMARGIN ) ;
+    unsigned int i_bar_value = ( f_motion / 100 ) * i_bar_width + i_bar_x1 ;
+    unsigned int i_bar_threshold = ( f_threshold / 100 ) * i_bar_width + i_bar_x1 ;
+    unsigned int i_bar_threshold_x1 = (float) i_bar_threshold * 0.98 ; /*thicken the threshold a little */
+    unsigned int i_bar_threshold_x2 = (float) i_bar_threshold * 1.02 ;
+    #undef HMARGIN
+    #undef VMARGIN
+    #undef BHEIGHT
+    /*fprintf( stderr, "static motionMeter value:%d thres:%d [%d-%d]\n", i_bar_value, i_bar_threshold,
+          i_bar_threshold_x1, i_bar_threshold_x2);
+    */
+    if ( !p_out_pic) return;
+
+    for (x = i_bar_x1; x <= i_bar_x2 ; x++)
+        for (y = i_bar_y1; y <= i_bar_y2; y++ )
+        {
+             if ( x <= i_bar_value ) // Draw Value
+                    p_y_pix[y*i_y_pitch+x] = 0xaf;
+             else if ( y == i_bar_y1 || y == i_bar_y2 || x == i_bar_x1 || x == i_bar_x2 ) // Draw surrounting rectangle
+                    p_y_pix[y*i_y_pitch+x] = 0xef;
+             if ( x >= i_bar_threshold_x1 && x <= i_bar_threshold_x2 ) // Draw Limit
+                    p_y_pix[y*i_y_pitch+x] = 0xff;
+        }
+}
+
+void motionMeterPacked( float f_motion, float f_threshold, picture_t* p_out_pic, filter_t* p_filter )
+{
+    /* Create a horizontial bar at the bottom of the picture showing the motion level */
+    const video_frame_format_t *p_fmt = &p_out_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    uint8_t* p_y_pix = p_out_pic->p[Y_PLANE].p_pixels;
+    const int i_y_pitch = p_out_pic->p[Y_PLANE].i_pitch;
+
+    unsigned int x,y;
+
+    if ( !p_out_pic) return;
+
+    #define HMARGIN  0.020  /* bar margin from left/right */
+    #define VMARGIN  0.010  /* bar margin from bottom */
+    #define BHEIGHT 0.025  /* bar height */
+    unsigned int i_bar_x1 = (float) i_width * HMARGIN ;
+    unsigned int i_bar_width = (float) i_width * ( 1 - 2 * HMARGIN ) ;
+    unsigned int i_bar_x2 = i_bar_x1 + i_bar_width ;
+    unsigned int i_bar_height = (float) i_height * ( BHEIGHT );
+    unsigned int i_bar_y1 = i_height - ( (float) i_height * VMARGIN + i_bar_height ) ;
+    unsigned int i_bar_y2 = i_height - ( (float) i_height * VMARGIN ) ;
+    unsigned int i_bar_value = ( f_motion / 100 ) * i_bar_width + i_bar_x1 ;
+    unsigned int i_bar_threshold = ( f_threshold / 100 ) * i_bar_width + i_bar_x1 ;
+    unsigned int i_bar_threshold_x1 = (float) i_bar_threshold * 0.98 ; /*thicken the threshold a little */
+    unsigned int i_bar_threshold_x2 = (float) i_bar_threshold * 1.02 ;
+    #undef HMARGIN
+    #undef VMARGIN
+    #undef BHEIGHT
+    /*fprintf( stderr, "static motionMeter value:%d thres:%d [%d-%d]\n", i_bar_value, i_bar_threshold,
+          i_bar_threshold_x1, i_bar_threshold_x2);
+    */
+    int i_y_offset, i_u_offset, i_v_offset;
+    if( GetPackedYuvOffsets( p_fmt->i_chroma,
+                             &i_y_offset, &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
+    {
+        msg_Warn( p_filter, "Unsupported input chroma (%4s)",
+                  (char*)&p_fmt->i_chroma );
+        return ;
+    }
+
+    for( x = i_bar_x1; x <= i_bar_x2; x+=2 )
+    {
+        for( y = i_bar_y1; y < i_bar_y2; y++ )
+        /* 1 macropixel = 4 bytes = 2 image pixels. For we proccess 2 image pixels per itteration*/
+        {
+            int i;
+            for ( i = 0; i < 2; i++)
+            {
+               if ( x <= i_bar_value ) // Draw Value
+                    p_y_pix[y*i_y_pitch+2*(x+i)+i_y_offset] = 0xaf;
+               else if ( y == i_bar_y1 || y == i_bar_y2 || x == i_bar_x1 || x == i_bar_x2 )
+                    p_y_pix[y*i_y_pitch+2*(x+i)+i_y_offset] = 0xef; // Draw surrounting rectangle
+               if ( x >= i_bar_threshold_x1 && x <= i_bar_threshold_x2 )
+                    p_y_pix[y*i_y_pitch+2*(x+i)+i_y_offset] = 0xff; // Draw Limit
+            }
+        }
+    }
+}
+
+#if 0
+void markPicture( diff_t* p_diff, picture_t* p_out_pic, diff_t i_motion_thres, filter_t * p_filter )
+{
+    const video_frame_format_t *p_fmt = &p_out_pic->format;
+    // NOTE:  We take format type from picture (not from filter )
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    uint8_t* p_y_pix = p_out_pic->p[Y_PLANE].p_pixels;
+    const int i_y_pitch = p_out_pic->p[Y_PLANE].i_pitch;
+
+    unsigned int x,y;
+    //msg_Dbg( p_filter, "In markPicture" );
+    if ( !p_out_pic) return;
+
+    for (y = 0; y < i_height; y++ )
+        for (x = 0; x < i_width ; x++)
+        {
+               if ( p_diff[y*i_width+x] > i_motion_thres )
+                    p_y_pix[y*i_y_pitch+x] = 0xff;
+        }
+}
+
+void markPicturePacked( diff_t* p_diff, picture_t* p_out_pic,diff_t i_motion_thres, filter_t * p_filter )
+{
+    const video_frame_format_t *p_fmt = &p_out_pic->format;
+    // NOTE:  We take format type from picture (not from filter )
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    uint8_t* p_y_pix = p_out_pic->p[Y_PLANE].p_pixels;
+    const int i_y_pitch = p_out_pic->p[Y_PLANE].i_pitch;
+
+    unsigned int x,y;
+    int i_y_offset, i_u_offset, i_v_offset;
+    //msg_Dbg( p_filter, "In markPicturePacked" );
+
+   if( GetPackedYuvOffsets( p_fmt->i_chroma,
+                             &i_y_offset, &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
+    {
+        msg_Warn( p_filter, "Unsupported input chroma (%4s)",
+                  (char*)&p_fmt->i_chroma );
+
+         return ;
+    }
+
+    for( y = 0; y < i_height; y++ )
+    {
+        for( x = 0; x < i_width; x+=2 )
+        // 1 macropixel = 4 bytes = 2 image pixels. For we proccess 2 image pixels per itteration
+        {
+            int i;
+            for ( i = 0; i < 2; i++)
+                if ( p_diff[y*i_width+x] > i_motion_thres )
+                     p_y_pix[y*i_y_pitch+2*(x+i)+i_y_offset] = 0xff ;
+        }
+    }
+
+}
+#endif
+
+float countMovedPixelsPercent( diff_t* p_diff, picture_t* p_ref_pic, diff_t i_motion_threshold )
+{
+    const video_frame_format_t *p_fmt = &p_ref_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+
+    unsigned int x,y,i_pix_count = 0;
+
+    for (y = 0; y < i_height; y++ )
+        for (x = 0; x < i_width ; x++)
+             if ( p_diff[y*i_width+x] > i_motion_threshold )
+                  i_pix_count++;
+    /*fprintf( stderr, "static detect: countMovedPixels: %d / %d [%f%%]\n", i_pix_count,
+                 ( i_height * i_width ), (float) i_pix_count / ( i_height * i_width ) * 100 );
+    */
+    /* Compute percentage of total pixel count */
+    return (float) ( i_pix_count ) / (float) ( i_height * i_width ) * 100 ;
+}
+
+void findDiffs (diff_t* p_diff, picture_t* p_new_pic, picture_t* p_old_pic, filter_t * p_filter )
+{
+    const video_frame_format_t *p_fmt = &p_new_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    const uint8_t* p_new_pix = p_new_pic->p[Y_PLANE].p_pixels;
+    const int i_new_pitch = p_new_pic->p[Y_PLANE].i_pitch;
+
+    const uint8_t *p_old_pix = p_old_pic->p[Y_PLANE].p_pixels;
+    const int i_old_pitch = p_old_pic->p[Y_PLANE].i_pitch;
+
+    /**
+     * Substract Y planes
+     */
+    unsigned x, y;
+    for( y = 0; y < i_height; y++ )
+    {
+        for( x = 0; x < i_width; x++ )
+            p_diff[y*i_width+x] = abs( p_new_pix[y*i_new_pitch+x] - p_old_pix[y*i_old_pitch+x] );
+    }
+
+    int i_chroma_dx;
+    int i_chroma_dy;
+    switch( p_new_pic->format.i_chroma )
+    /* NOTE: We check here with picture->format.i_chrome and we initialized with p_filter->fmt_in.video.i_chroma */
+    {
+        case VLC_FOURCC('I','4','2','0'):
+        case VLC_FOURCC('I','Y','U','V'):
+        case VLC_FOURCC('J','4','2','0'):
+        case VLC_FOURCC('Y','V','1','2'):
+            i_chroma_dx = 2;
+            i_chroma_dy = 2;
+            break;
+
+        case VLC_FOURCC('I','4','2','2'):
+        case VLC_FOURCC('J','4','2','2'):
+            i_chroma_dx = 2;
+            i_chroma_dy = 1;
+            break;
+
+        default:
+            //FIX: Is it ok to hang to the p_new_pic ??
+            msg_Warn( p_filter, "Not taking chroma into account" );
+            i_chroma_dx = 0;
+            i_chroma_dy = 0;
+            break;
+    }
+    /* Subtrack Cb (U) and Cr (V) planes */
+
+
+    if( i_chroma_dx != 0 && i_chroma_dy != 0 )
+    {
+        const uint8_t *p_new_pix_u = p_new_pic->p[U_PLANE].p_pixels;
+        const uint8_t *p_new_pix_v = p_new_pic->p[V_PLANE].p_pixels;
+        const int i_new_pitch_u = p_new_pic->p[U_PLANE].i_pitch;
+        const int i_new_pitch_v = p_new_pic->p[V_PLANE].i_pitch;
+
+        const uint8_t *p_old_pix_u = p_old_pic->p[U_PLANE].p_pixels;
+        const uint8_t *p_old_pix_v = p_old_pic->p[V_PLANE].p_pixels;
+        const int i_old_pitch_u = p_old_pic->p[U_PLANE].i_pitch;
+        const int i_old_pitch_v = p_old_pic->p[V_PLANE].i_pitch;
+
+        for( y = 0; y < i_height/i_chroma_dy; y++ )
+        {
+            for( x = 0; x < i_width/i_chroma_dx; x ++ )
+            {
+                const diff_t d = abs( p_new_pix_u[y*i_new_pitch_u+x] - p_old_pix_u[y*i_old_pitch_u+x] ) +
+                                 abs( p_new_pix_v[y*i_new_pitch_v+x] - p_old_pix_v[y*i_old_pitch_v+x] );
+                int i, j;
+
+                for( j = 0; j < i_chroma_dy; j++ )
+                {
+                    for( i = 0; i < i_chroma_dx; i++ )
+                        p_diff[i_chroma_dy*i_width*j + i_chroma_dx*i] += d;
+                }
+            }
+        }
+    }
+}
+
+void findDiffsPacked (diff_t* p_diff, picture_t* p_new_pic, picture_t* p_old_pic, filter_t * p_filter )
+{
+    const video_frame_format_t *p_fmt = &p_new_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const unsigned int i_height = p_fmt->i_height;
+    const unsigned int i_width = p_fmt->i_width;
+
+    const uint8_t* p_new_pix = p_new_pic->p[Y_PLANE].p_pixels;
+    const int i_new_pitch = p_new_pic->p[Y_PLANE].i_pitch;
+
+    const uint8_t *p_old_pix = p_old_pic->p[Y_PLANE].p_pixels;
+    const int i_old_pitch = p_old_pic->p[Y_PLANE].i_pitch;
+
+    int i_y_offset, i_u_offset, i_v_offset;
+    unsigned x, y;
+
+    if( GetPackedYuvOffsets( p_fmt->i_chroma,
+                             &i_y_offset, &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
+    {
+        msg_Warn( p_filter, "Unsupported input chroma (%4s)",
+                  (char*)&p_fmt->i_chroma );
+        return ;
+    }
+
+    /* Subtract all planes at once */
+
+    for( y = 0; y < i_height; y++ )
+    {
+        for( x = 0; x < i_width; x+=2 )
+        /* 1 macropixel = 4 bytes = 2 image pixels. For we proccess 2 image pixels per itteration */
+        {
+            int i;
+            diff_t d;
+
+            d = abs( p_new_pix[y*i_new_pitch+2*x+i_u_offset] - p_old_pix[y*i_old_pitch+2*x+i_u_offset] ) + /* U */
+                abs( p_new_pix[y*i_new_pitch+2*x+i_v_offset] - p_old_pix[y*i_old_pitch+2*x+i_v_offset] );  /* V */
+
+            for( i = 0; i < 2; i++ )
+                p_diff[y*i_width+x+i] =
+                   abs( p_new_pix[y*i_new_pitch+2*(x+i)+i_y_offset] - p_old_pix[y*i_old_pitch+2*(x+i)+i_y_offset] ) + d;
+        }
+    }
+
+}
+
+static int StaticDetectCallback( vlc_object_t *p_this, char const *psz_var,
+                               vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+	VLC_UNUSED( oldval );
+	filter_t* p_filter = (filter_t*) p_data ;
+	filter_sys_t* p_sys = p_filter->p_sys ;
+	if ( !strcmp( psz_var, FILTER_PREFIX PAR_DTHRESHOLD) ) {
+		float f_pixsens_pcnt = newval.f_float ;
+		p_sys->i_pix_diff_thres =  ( 100 - f_pixsens_pcnt ) * MAX_ABSOLUTE_PIX_DIFF / 100 ;
+		msg_Dbg( p_this, "\t[static] Pixel Difference Threshold= %d\n", p_sys->i_pix_diff_thres ) ;
+		return VLC_SUCCESS;
+	}
+	else if ( !strcmp( psz_var, FILTER_PREFIX PAR_TAKESNAPSHOT) ) {
+		if (!p_sys->b_has_old_pic) //too early !
+            return VLC_EGENERIC ;
+        var_SetInteger( (vout_thread_t*) p_filter->p_owner, "snapshot-width", 0 );
+        var_SetInteger( (vout_thread_t*) p_filter->p_owner, "snapshot-height", 0 ) ;
+        vout_Snapshot( (vout_thread_t*) p_filter->p_owner, p_sys->p_old_pic );
+		msg_Dbg( p_this, "\t[static] Custom snapshot taken" ) ;
+		return VLC_SUCCESS;
+	}
+	return VLC_ENOVAR ;
+}
+
+#ifdef NOIZ
+/*****************************************************************************
+ * Gaussian Convolution
+ *****************************************************************************
+ *    Gaussian convolution ( sigma == 1.4 )
+ *
+ *    |  2  4  5  4  2  |   |  2  4  4  4  2 |
+ *    |  4  9 12  9  4  |   |  4  8 12  8  4 |
+ *    |  5 12 15 12  5  | ~ |  4 12 16 12  4 |
+ *    |  4  9 12  9  4  |   |  4  8 12  8  4 |
+ *    |  2  4  5  4  2  |   |  2  4  4  4  2 |
+ *****************************************************************************/
+static void GaussianConvolution( diff_t *p_inpix,
+                                 picture_t* p_ref_pic )
+{
+    const video_frame_format_t *p_fmt = &p_ref_pic->format;
+    /* NOTE:  We take format type from picture (not from filter ) */
+    const int i_num_lines = p_fmt->i_height;
+    const int i_src_pitch = p_fmt->i_width;
+    const int i_src_visible = p_fmt->i_visible_width ;
+
+    int x,y;
+    diff_t* p_smooth = calloc( i_src_pitch * i_num_lines, sizeof( *p_smooth ) );
+    if ( !p_smooth )
+            return;
+
+    for( y = 2; y < i_num_lines - 2; y++ )
+    {
+        for( x = 2; x < i_src_visible - 2; x++ )
+        {
+            p_smooth[y*i_src_visible+x] = (uint32_t)(
+              /* 2 rows up */
+                ( p_inpix[(y-2)*i_src_pitch+x-2] )
+              + ((p_inpix[(y-2)*i_src_pitch+x-1]
+              +   p_inpix[(y-2)*i_src_pitch+x]
+              +   p_inpix[(y-2)*i_src_pitch+x+1])<<1 )
+              + ( p_inpix[(y-2)*i_src_pitch+x+2] )
+              /* 1 row up */
+              + ((p_inpix[(y-1)*i_src_pitch+x-2]
+              + ( p_inpix[(y-1)*i_src_pitch+x-1]<<1 )
+              + ( p_inpix[(y-1)*i_src_pitch+x]*3 )
+              + ( p_inpix[(y-1)*i_src_pitch+x+1]<<1 )
+              +   p_inpix[(y-1)*i_src_pitch+x+2]
+              /* */
+              +   p_inpix[y*i_src_pitch+x-2]
+              + ( p_inpix[y*i_src_pitch+x-1]*3 )
+              + ( p_inpix[y*i_src_pitch+x]<<2 )
+              + ( p_inpix[y*i_src_pitch+x+1]*3 )
+              +   p_inpix[y*i_src_pitch+x+2]
+              /* 1 row down */
+              +   p_inpix[(y+1)*i_src_pitch+x-2]
+              + ( p_inpix[(y+1)*i_src_pitch+x-1]<<1 )
+              + ( p_inpix[(y+1)*i_src_pitch+x]*3 )
+              + ( p_inpix[(y+1)*i_src_pitch+x+1]<<1 )
+              +   p_inpix[(y+1)*i_src_pitch+x+2] )<<1 )
+              /* 2 rows down */
+              + ( p_inpix[(y+2)*i_src_pitch+x-2] )
+              + ((p_inpix[(y+2)*i_src_pitch+x-1]
+              +   p_inpix[(y+2)*i_src_pitch+x]
+              +   p_inpix[(y+2)*i_src_pitch+x+1])<<1 )
+              + ( p_inpix[(y+2)*i_src_pitch+x+2] )
+              ) >> 6 /* 115 */;
+        }
+    }
+    memcpy( p_inpix, p_smooth, i_src_pitch * i_num_lines * sizeof( *p_inpix ) );
+    free( p_smooth );
+
+}
+#endif
-- 
1.5.6.5

