[vlc-devel] [PATCH] Added Static Detect Video FIlter

noxelia at gmail.com noxelia at gmail.com
Tue Aug 19 16:32:53 CEST 2008


From: basOS G <noxelia 4t gmail . com>

---
 configure.ac                         |    4 +-
 modules/video_filter/Modules.am      |    2 +
 modules/video_filter/beep.c          |  141 ++++++
 modules/video_filter/beep.h          |   15 +
 modules/video_filter/static_detect.c |  827 ++++++++++++++++++++++++++++++++++
 5 files changed, 988 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 1518f44..4cd5759 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1126,6 +1126,8 @@ 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 2268d9a..fb52578 100644
--- a/modules/video_filter/Modules.am
+++ b/modules/video_filter/Modules.am
@@ -44,4 +44,6 @@ SOURCES_chain = chain.c
 SOURCES_postproc = postproc.c
 SOURCES_swscale = swscale.c ../codec/avcodec/chroma.h
 SOURCES_imgresample = imgresample.c ../codec/avcodec/chroma.h
+SOURCES_staticdetect = static_detect.c beep.c
 noinst_HEADERS = filter_common.h filter_picture.h
diff --git a/modules/video_filter/beep.c b/modules/video_filter/beep.c
new file mode 100644
index 0000000..fd469a4
--- /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 at 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..30c0054
--- /dev/null
+++ b/modules/video_filter/static_detect.c
@@ -0,0 +1,827 @@
+/*****************************************************************************
+ * motion_blur.c : static detect filter for VLC
+ *****************************************************************************
+ * Copyright (C) 2008 the VideoLAN team
+ * $Id$
+ *
+ * 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_sout.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 ); */
+//TODO :static int StaticDetectCallback( vlc_object_t *, char const *,
+//                               vlc_value_t, vlc_value_t, void * );
+
+
+/*****************************************************************************
+ * 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")
+#define DTHRESHOLD_LONGTEXT N_("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 FILTER_PREFIX "staticdetect-"
+#define PAR_MTHRESHOLD "tolerance"
+#define PAR_TTHRESHOLD "snaptime"
+#define PAR_DTHRESHOLD "sensivity"
+#define PAR_FREEZETIME "freezetime"
+#define PAR_MMETER "motionmeter"
+
+/* default difference threshold */
+#define DEFAULT_DIFF_THRESHOLD 9
+/* 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
+
+
+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 );
+
+    //TOCHECK : WHAT IS advc (last parameter of add integer ) @ vlc_plugin.h
+    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, false );
+    add_integer_with_range ( FILTER_PREFIX PAR_DTHRESHOLD, DEFAULT_DIFF_THRESHOLD, 0, 768, NULL,
+			DTHRESHOLD_TEXT, DTHRESHOLD_LONGTEXT, false );
+    add_bool ( FILTER_PREFIX PAR_MMETER, DEFAULT_MMETER, NULL,
+                        MOTIONM_TEXT, NULL, false );
+    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,
+     NULL
+};
+
+
+/*****************************************************************************
+ * filter_sys_t
+ *****************************************************************************/
+struct filter_sys_t
+{
+    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 */
+    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 */
+    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_CreateGetFloatCommand( p_filter, FILTER_PREFIX PAR_MTHRESHOLD );
+    int i_time_threshold =
+        var_CreateGetIntegerCommand( 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_CreateGetIntegerCommand( 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 ) ;
+    p_filter->p_sys->i_pix_diff_thres =
+        var_CreateGetIntegerCommand( p_filter, FILTER_PREFIX PAR_DTHRESHOLD );
+    bool b_meter = var_CreateGetBoolCommand( p_filter, FILTER_PREFIX PAR_MMETER );
+    if ( !b_meter)  pf_motionMeter = NULL;
+
+
+    //TODO : Check for callback meaning. Do we need it ?
+    /*var_AddCallback( p_filter, FILTER_PREFIX "factor",
+                     MotionBlurCallback, p_filter->p_sys );
+    */
+    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 );
+                  vout_Snapshot( (vout_thread_t*) p_filter->p_owner, p_in_pic );
+                  //vout_Control( (vout_thread_t*) p_filter->p_owner, VOUT_SNAPSHOT );
+                  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 )
+{
+    /* 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
+            }
+        }
+    }
+}
+
+/*
+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 ;
+        }
+    }
+
+}
+*/
+
+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;
+    //msg_Dbg( p_filter, "In findDiffs" );
+    /**
+     * 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;
+    //msg_Dbg( p_filter, "In findDiffsPacked" );
+    if( GetPackedYuvOffsets( p_fmt->i_chroma,
+                             &i_y_offset, &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
+    {
+        //FIX: Is it ok to hang to the p_new_pic ??
+        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;
+        }
+    }
+
+}
+
+#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
+
+//TODO: On The fly parameter Change
+/*static int MotionBlurCallback( vlc_object_t *p_this, char const *psz_var,
+                               vlc_value_t oldval, vlc_value_t newval,
+                               void *p_data )
+{
+    VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+    filter_sys_t *p_sys = (filter_sys_t *)p_data;
+    if( !strcmp( psz_var, FILTER_PREFIX "factor" ) )
+        p_sys->i_factor = __MIN( 127, __MAX( 1, newval.i_int ) );
+    return VLC_SUCCESS;
+}*/
-- 
1.5.4.3




More information about the vlc-devel mailing list