[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