#include "mylib.h"

static unsigned char rgb_buf	 [3*1024*768];	// main vid_widthxvid_height live display image buffer
static unsigned char ds_buf 	 [3*1024*768];	// temp for downsized live image
static unsigned char ds1_buf	 [3*1024*768];	// temp for downsized live image corrected for avg intensity
static unsigned char ref_buf	 [3*1024*768];	// temp for reference picture buffer (time averaged)
static unsigned char res_buf	 [3*1024*768];	// temp for motion analysis picture buffer (graphical results)
static unsigned char grf_buf	 [3*1024*768];	// strip chart graph buffer
static unsigned char gray_buf	 [3*1024*768];	// Gray scale Buffer
static unsigned char gray_1b	 [1*1024*768];	// Gray scale Buffer
static unsigned int  histogram	 [255];		// Gray scale Buffer
static unsigned char hist_buf	 [3*1024*768];	// Histogram GrayScale density


int 		alarm_threshold=70;
float 		ref_update_fraction=0.20;
float 		sig_pix_threshold=25;
struct 		alarm_zone alarm_zone;
struct 		video_capability video_caps;
struct 		video_picture v_pict;
unsigned int	avg_ds_intensity;
unsigned int  	avg_ref_intensity;
unsigned int	avg_ds1_intensity;
float 		graph_scale=1;
unsigned int	alarm_pix = 0;
int 		show_target_box=true;
int 		beep_on_alarm=true;
int 		periodic_save_interval=200;

static int 	u_first = 1;
static int 	d_first = 1;

void		*module;


char *get_rgb_addr(void)
{
  return (char *)&rgb_buf;
}

char *get_ds_addr(void)
{
  return (char *)&ds_buf;
}

char *get_rgb1_addr(void)
{
  return (char *)&ds1_buf;
}
char *get_gray_addr(void)
{
  return (char *)&gray_buf;
}

char *get_gray1_addr(void)
{
  return (char *)&gray_1b;
}

char *get_ref_addr(void)
{
  return (char *)&ref_buf;
}

char *get_res_addr(void)
{
  return (char *)&res_buf;
}

char *get_grf_addr(void)
{
  return (char *)&grf_buf;
}

char *get_hist_addr(void)
{
  return (char *)&hist_buf;
}

int v4l_open(char *device)
{
	int dev = -1;
	int max_try = 5;

	while (max_try) 
	{
		dev = open (device, O_RDWR);
		if (dev == -1) 
		{
			if (!--max_try) 
			{
				fprintf (stderr, "Can't open device '%s'\n", device);
				return -1;
				break;
			}
			sleep (1);
		} 
		else 
		{
			break;
		}
	}
	
	fprintf (stderr,"Device opened ,device name =  '%s' with id=%d\n", device,dev);
	
	return dev;
	
}


void v4l_close(int dev)
{
	if (dev > 0)
		close(dev);
}


int get_vid_cap(int dev)
{
    if (ioctl (dev, VIDIOCGCAP, &video_caps) == -1) 
	{
		printf("ioctl (VIDIOCGCAP) failed\n");
		return -1;
	}
    return 0;
}

int get_brigthness(int dev,int channel)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  return vid_chnl.brightness;
}

int get_hue(int dev,int channel)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  return vid_chnl.hue;
}

int get_contras(int dev,int channel)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  return vid_chnl.contrast;
}

int get_color(int dev,int channel)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  return vid_chnl.colour;
}

int set_brigthness(int dev,int channel,int value)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  vid_chnl.brightness=value;
  ioctl (dev, VIDIOCSPICT, &vid_chnl);
  return vid_chnl.brightness;
}

int set_hue(int dev,int channel,int value)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  vid_chnl.hue=value;
  ioctl (dev, VIDIOCSPICT, &vid_chnl);
  return vid_chnl.hue;
}

int set_contras(int dev,int channel,int value)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  vid_chnl.contrast=value;
  ioctl (dev, VIDIOCSPICT, &vid_chnl);
  return vid_chnl.contrast;
}

int set_color(int dev,int channel,int value)
{
  struct video_picture vid_chnl;
  struct video_channel vid_cnl; 
 
  if (ioctl (dev, VIDIOCGCHAN, &vid_cnl) == -1) 
  {
	printf("ioctl (VIDIOCGCHAN) failed\n");
  }
  if (vid_cnl.channel != channel){
    vid_cnl.channel = channel;
    if (ioctl (dev, VIDIOCSCHAN, &vid_cnl) == -1){
	printf("ioctl (VIDIOCSCHAN) failed");
    }
  }
  ioctl (dev, VIDIOCGPICT, &vid_chnl);
  vid_chnl.colour=value;
  ioctl (dev, VIDIOCSPICT, &vid_chnl);
  return vid_chnl.colour;
}

char *get_image(int dev, int *width, int *height, int input,int norm,int fmt,int *size)
{
	struct video_capability vid_caps;
	struct video_mbuf vid_buf;
	struct video_mmap vid_mmap;
	struct video_channel vid_chnl;
	char *map = NULL;
	int len;
	*size = 0;	
	                
	if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) 
	{
		printf("ioctl (VIDIOCGCAP) failed\n");
		return (NULL);
	}
	if (input != IN_DEFAULT) 
	{
		vid_chnl.channel = 3;
		if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) 
		{
			printf("ioctl (VIDIOCGCHAN) failed\n");
		} 
		else 
		{
			vid_chnl.norm    = norm;
			if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) 
			{
				printf("ioctl (VIDIOCSCHAN) failed");
				return (NULL);
			}
		}
	}
	
	if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) 
	{
		map = malloc (vid_caps.maxwidth * vid_caps.maxheight * 3);
		len = read (dev, map, vid_caps.maxwidth * vid_caps.maxheight * 3);
		if (len <=  0) 
		{
			free (map);
			return (NULL);
		}
		*size = 0;
		return (map);
	}

	map = mmap (0, vid_buf.size, PROT_READ|PROT_WRITE,MAP_SHARED,dev,0);
	if ((unsigned char *)-1 == (unsigned char *)map) 
	{
		printf("mmap() failed \n");
		return (NULL);
	}

	vid_mmap.format = fmt;
	vid_mmap.frame = 0;
	
	vid_caps.maxwidth=320;
	vid_caps.maxheight=240;
	
	vid_mmap.width = vid_caps.maxwidth;
	vid_mmap.height = vid_caps.maxheight;
		  
	*width=vid_mmap.width;
	*height=vid_mmap.height;
	
	if (ioctl (dev, VIDIOCMCAPTURE, &vid_mmap) == -1) 
	{
		printf("VIDIOCMCAPTURE failed\n");
		munmap (map, vid_buf.size);
		return (NULL);
	}
	if (ioctl (dev, VIDIOCSYNC, &vid_mmap) == -1) 
	{
		printf("VIDIOCSYNC failed \n");
		munmap (map, vid_buf.size);
		return (NULL);
	}
	
	*size = vid_buf.size;
	return (map);
}

int retrieve_data(int dev,int chan,int p_width,int p_height,int g_width,int g_height,int gray_sample,int do_motion,int char_detect){

	
	int size;
	char *image;
	char tmp;
	char *img_ptr,*img_ptr1;
	int cnt;
	int vid_width=0;
	int vid_height=0;
	int oblob_cnt,
	    ograph_scale,
	    oalarm_threshold,
	    pixcnt,
	    image_cnt;
	float fresult;
	int last_mode=0;
	int success=-1;
	
	
	if (dev <= 0)
	{
		printf("Unable to use v4l camera device... open failed???");	
		return TRUE;
	}

	if(!v_pict.palette)
	{
		if(ioctl(dev, VIDIOCGPICT, &v_pict)==-1)
		{
			printf("Unable to get picture properties from webcam (VIDIOCGPICT failed)\n");
			return TRUE;
		}
		last_mode=v_pict.palette;
		if(v_pict.palette!=VIDEO_PALETTE_YUV420P && v_pict.palette!=VIDEO_PALETTE_RGB24 && v_pict.palette!=VIDEO_PALETTE_RGB32)
		{
			v_pict.palette=VIDEO_PALETTE_RGB24;
			success=ioctl(dev, VIDIOCSPICT, &v_pict);
			if(success!=-1)
			{
			  printf("Now Sysyem Runing With RGB24\n");
			}
			if (success==-1)
			{
			    printf("RGB24 not supported, trying YUV420P...\n");
			    v_pict.palette=VIDEO_PALETTE_YUV420P;
			    success=ioctl(dev, VIDIOCSPICT, &v_pict);
			    if(success!=-1)
			    {
				printf("Now Sysyem Runing With YUV420P\n");
			    }
			}
			if (success==-1)
			{
			    printf("YUV420P not supported, trying RGB32...\n");
			    v_pict.palette=VIDEO_PALETTE_RGB32;
			    success=ioctl(dev, VIDIOCSPICT, &v_pict);
			    if(success!=-1)
			    {
				printf("Now Sysyem Runing With RGB32\n");
			    }
			}
			if (success!=-1)
			{
			    v_pict.palette=last_mode;
			    printf("OH... no, your camera device not supported by this software\n");
			}
		}
	}

	image = get_image(dev,&vid_width,&vid_height,chan,NORM_DEFAULT,v_pict.palette,&size);
	
	if ( image )
	{
		if(v_pict.palette==VIDEO_PALETTE_YUV420P)
			ccvt_420p_rgb24(vid_width,vid_height,image,image+(vid_width*vid_height),image+(vid_width*vid_height),rgb_buf);
		else
		if(v_pict.palette==VIDEO_PALETTE_RGB32)
		{
			img_ptr 	= rgb_buf;
			img_ptr1	= image;
			for (cnt=0; cnt < vid_width*vid_height; cnt++)
			{
				img_ptr[0] = img_ptr1[2];
				img_ptr[1] = img_ptr1[1];
				img_ptr[2] = img_ptr1[0];
				img_ptr += 3;
				img_ptr1+=4;
			}
		}
		else
		{
			memcpy(rgb_buf,image,vid_width*vid_height*3);
			img_ptr = rgb_buf;
			for (cnt=0; cnt < vid_width*vid_height; cnt++)
			{
				tmp = img_ptr[0];
				img_ptr[0] = img_ptr[2];
				img_ptr[2] = tmp;
				img_ptr += 3;
			}
		}
	}
	else
		printf("image capture failed\n");
	
	if (size)
    	  munmap(image, size);
	else 
	if (image)
    	  free(image);

	down_sample_image(vid_width,vid_height,p_width,p_height);
	  
	if (gray_sample==1)
	{
	  generate_grayscale(p_width,p_height);
	  calculate_histogram(p_width,p_height);
	}
	
	if (do_motion==1)
	{
 	   do_motion_analysis(p_width,p_height,p_width,p_height,&oblob_cnt,&ograph_scale,&oalarm_threshold,&pixcnt,&image_cnt,&fresult);
	
	   update_history_graph(oblob_cnt*ograph_scale,oalarm_threshold,g_width,g_height);	
	   
	   update_reference_image(p_width,p_height,p_width,p_height);
	}
	
	if (char_detect==1)
	{
	  //search_text(gray_1b,p_width,p_height,&buf,overide_thr);
	  //memcpy(gray_1b,&buf,p_width*p_height);
	  //one_2_tree_bytes(p_width,p_height );
	}
	
	return TRUE;
}


void down_sample_image(int vid_width,int vid_height,int prevX,int prevY)
{
	int x,y;
	unsigned char *p0;
	unsigned char *p1;
	unsigned char *p2;
	unsigned char *p3;
	unsigned char *p4;
	unsigned char *pdest;
	unsigned int avg = 0;
	unsigned char correction;
	
	
	pdest = &ds_buf[0];
	for (y=0; y< prevY;y++)
	{
	
		p1 = rgb_buf + (y*vid_height/prevY)*vid_width*3 ;
		p2 = p1 + 3;			            	
		p3 = p1 + (vid_width * 3);			
		p4 = p3 + 3;				
		for (x=0; x<prevX; x++)
		{
			
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;
			*pdest++ = (*p1++ + *p2++ + *p3++ + *p4++) / 4;
			
			p1 = rgb_buf + ((y*vid_height/prevY)*vid_width*3) +((x*vid_width/prevX)*3);
			p2 = p1 + 3;
			p3 = p1 + (vid_width * 3);
			p4 = p3 + 3;
		}
	}
	
	for ( p1 = &ds_buf[0]; p1 < &ds_buf[0]+sizeof(ds_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ds_buf);
	avg_ds_intensity = avg;
	p0 = &ds_buf[0];
	p1 = &ds1_buf[0];
	if (avg_ds_intensity < avg_ref_intensity)
	{
		correction = avg_ref_intensity - avg_ds_intensity;
		for ( ; p1 < &ds1_buf[0]+sizeof(ds1_buf);p1++,p0++ )
		{
			*p1 = *p0 + correction;
			if ( *p1 < *p0 ) *p1 = 255;
		}
	}
	else if(avg_ds_intensity == avg_ref_intensity)
	{
		memcpy(p1,p0,sizeof(ds1_buf));
	}
	
	else if(avg_ds_intensity > avg_ref_intensity)
	{
		correction = avg_ds_intensity - avg_ref_intensity;
		for (; p1 < &ds1_buf[0]+sizeof(ds1_buf); p1++,p0++ )
		{
			*p1 = *p0 - correction;
			if ( *p1 > *p0 ) *p1 = 0;
		}
	
	}
	for ( p1 = &ds1_buf[0]; p1 < &ds1_buf[0]+sizeof(ds1_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ds1_buf);
	avg_ds1_intensity = avg;
}

void generate_grayscale(int vid_width,int vid_height )
{
  int x,y;
  int tval;
  
  
  for (y=0;y<vid_height;y++)
  {
    for (x=0;x<vid_width;x++)
    {
      tval=0;
      tval+=ds_buf[(y*vid_width*3)+(x*3)+0];
      tval+=ds_buf[(y*vid_width*3)+(x*3)+1];
      tval+=ds_buf[(y*vid_width*3)+(x*3)+2];
      tval=tval/3;
      gray_buf[(y*vid_width*3)+(x*3)+0]=tval;
      gray_buf[(y*vid_width*3)+(x*3)+1]=tval;
      gray_buf[(y*vid_width*3)+(x*3)+2]=tval;
      gray_1b[(y*vid_width)+(x)]=tval;
    }
  }
}

void mark_alarm_zone( struct alarm_zone *zone,int vid_width,int vid_height )
{
	int x,y;
	char *p1,*p2;

	if (zone->x1 < 0 || zone->x2 < 0 || zone->y1 < 0 || zone->y2 < 0 )
		return;
	if (zone->x1 > vid_width-1 || zone->x2 > vid_width-1 || zone->y1 > vid_height-1 || zone->y2 > vid_height-1 )
		return;
		
	p1 = rgb_buf + (zone->y1)*vid_width*3;
	p2 = rgb_buf + (zone->y2)*vid_width*3;
	for( x = 0; x < vid_width; x++)
	{
		*p1 = ~*p1;
		*(p1+1) = ~*(p1+1);
		*(p1+2) = ~*(p1+2);

		*p2 = ~*p2;
		*(p2+1) = ~*(p2+1);
		*(p2+2) = ~*(p2+2);

		p1 += 3;
		p2 += 3;
	}

	p1 = rgb_buf + (zone->x1)*3;
	p2 = rgb_buf + (zone->x2)*3;
	for( y = 0; y < vid_height; y++)
	{
		*p1 = ~*p1;
		*(p1+1) = ~*(p1+1);
		*(p1+2) = ~*(p1+2);
		
		*p2 = ~*p2;
		*(p2+1) = ~*(p2+1);
		*(p2+2) = ~*(p2+2);
		
		p1 += vid_width*3;
		p2 += vid_width*3;
	}
}

void update_history_graph(int percent, int alarm_level,int prevX,int prevY)
{
 	static int first = 1;
	int		y;
	unsigned char *ptr;
	static int call_cnt = 0;
	
	call_cnt++;
	
	if (first)
	{
		memset(&grf_buf[0],0,sizeof(grf_buf));
		first = 0;
	}
	
  	for (y=0; y<prevY; y++)
  	{
	  	memmove( grf_buf+y*prevX*3,grf_buf+y*prevX*3+3,(prevX-1)*3);

	  	ptr = grf_buf + y*prevX*3 + (prevX-1)*3;
	  	*ptr++ = 0;
	  	*ptr++ = 0;
	  	*ptr++ = 0;

  	}

	if (percent < 0)
		percent = 0;
	if (percent > 99)
		percent = 99;

	ptr = grf_buf + ((99-percent)/2)*prevX*3 + (prevX-1)*3;
	while ( ptr < grf_buf + sizeof(grf_buf))
	{
		if ( percent > alarm_level )
		{		
			*ptr = 255;
			*(ptr+1) = 32;
			*(ptr+2) = 32;
		}
		else
		{
			*ptr = 32;
			*(ptr+1) = 255;
			*(ptr+2) = 32;
		}
		ptr += prevX * 3;
	}		

	if ( call_cnt %4 == 0)
	{
		if ( alarm_level < 0)
			alarm_level = 0;
		if (alarm_level > 99)
			alarm_level = 99;
		ptr = grf_buf + ((99-alarm_level)/2)*prevX*3 + (prevX-1)*3;
		*ptr++ = 32;
		*ptr++ = 255;
		*ptr = 255;
	}
}

float do_motion_analysis(int vid_width,int vid_height,int prevX,int prevY,int *oblob_cnt,int *ograph_scale,int *oalarm_threshold,int *opixcnt,int *oimage_cnt,float *ofresult)
{
  	
	int x,y;
	unsigned char 	*pdest;
	unsigned char 	*psrc;
	unsigned char 	*pref;
	unsigned char 	red;
	unsigned char 	green;
	unsigned char 	blue;
	unsigned char 	cresult;
	float  		fresult = 0.0f;
	int		pixcnt;
	unsigned char 	threshold;
	int    		blob_cnt;
	int 		i;	
	time_t      	t;
	struct tm  	*tm;
	static	int 	image_cnt = 0;
	char 		*cp;
        
    	
	if ( d_first == 1 )
	{
		d_first = 0;
		return 0.0;
	}
	
	alarm_zone.x1 = vid_width;
	alarm_zone.x2 = -1;
	alarm_zone.y1 = vid_height;
	alarm_zone.y2 = -1;

	pref  = &ref_buf[0];
	psrc  = &ds1_buf[0];
	pdest = &res_buf[0];
	
	for (y=0; y<prevY; y++)
	{
		for (x=0; x<prevX; x++)
		{
			red = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;
			pref++; psrc++;
			green = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;
			pref++; psrc++;
			blue  = (*pref > *psrc) ? *pref- *psrc : *psrc- *pref;
			pref++; psrc++;
			cresult = sqrt((red*red + green*green + blue*blue)/3);
			*pdest++ = cresult;
			*pdest++ = cresult;			
			*pdest++ = cresult;
			fresult += (float)cresult;
		}
	}
	
	
	fresult = fresult/(float)(prevX*prevY);

	threshold = (unsigned char)sig_pix_threshold;
	pixcnt = 0;
	psrc  = &res_buf[0];
	while ( psrc < res_buf+sizeof(res_buf))
	{
		if ( *psrc > threshold )		
		{
			pixcnt++;
			*psrc = 255;
			*(psrc+1) = 255;
			*(psrc+2) = 255;
		}
			
		psrc += 3;
	}
	
	blob_cnt = 0;
	psrc  = res_buf + prevX * 3;
	while ( psrc < (res_buf+sizeof(res_buf)-prevX*3))
	{
		for (i=0;i<1;i++)
		{
			if (*psrc < 255) break;
			if (*(psrc-prevX*3) < 255) break;
			if (*(psrc+prevX*3) < 255) break;
			if (*(psrc-3) < 255) break;
			if (*(psrc+3) < 255) break;
			if (*(psrc-prevX*3+3) < 255) break;
			if (*(psrc-prevX*3-3) < 255) break;
			if (*(psrc+prevX*3+3) < 255) break;
			if (*(psrc+prevX*3-3) < 255) break;
	
			*(psrc+2) = 0;
			*(psrc+1) = 0;
			blob_cnt++;			
			x = ((psrc - res_buf) % (prevX * 3))/3;
			y = (psrc - res_buf) / (prevX * 3);
			if ( x < alarm_zone.x1 )
				alarm_zone.x1 = x;
			if ( alarm_zone.x2 < x )
				alarm_zone.x2 = x;
			if ( y < alarm_zone.y1 )
				alarm_zone.y1 = y;
			if ( alarm_zone.y2 < y )
				alarm_zone.y2 = y;		
			}
		psrc += 3;
	}
	

	if (blob_cnt*graph_scale > alarm_threshold)
	{
		alarm_pix++;
                if ( show_target_box )
		    mark_alarm_zone(&alarm_zone,vid_width,vid_height);
		
		add_rgb_text(rgb_buf,vid_width,vid_height, 1);
		
		if (beep_on_alarm)
		{
			//beep();
		}
	}
	else
		add_rgb_text(rgb_buf,vid_width,vid_height, 0);
		
	
	image_cnt++;

	if (( blob_cnt*graph_scale > alarm_threshold ) || 
		((image_cnt % periodic_save_interval) == 0))
	{
    	time(&t);
    	tm = localtime(&t);
    	//strftime(line,sizeof(line)-1,"GSPY%H%M%S.jpg",tm);	
	//	put_image_jpeg(line, rgb_buf, vid_width, vid_height, 80);
	
	}
    	
    *oblob_cnt=blob_cnt;
    *ograph_scale=graph_scale;
    *oalarm_threshold=alarm_threshold;
    *oimage_cnt=image_cnt;
    *ofresult=fresult;
    *opixcnt=pixcnt;
        
    return fresult;
}

void update_reference_image(int vid_width,int vid_height,int prevX,int prevY)
{
  	int x,y;
	unsigned char *pdest;
	unsigned char *psrc;
	float old;
	unsigned int avg = 0;
	unsigned char *p1;
	
	if ( u_first == 1 )
	{
		memcpy(ref_buf,ds_buf,prevX*prevY*3);
		u_first = 0;
	}
	else
	{		
		// now update reference buffer by using some of old image and some of new
		psrc  = &ds_buf[0];
		pdest = &ref_buf[0];			
		old = 1.0 - ref_update_fraction;
		for (y=0; y< prevY; y++)
		{
			for (x=0; x< prevX ; x++)
			{
				// give the fpu something to do...
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// red
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// green
				*pdest++ = old * *pdest + ref_update_fraction * *psrc++ + 0.5;	// blue
			}
		}
	}


	for ( p1 = &ref_buf[0]; p1 < &ref_buf[0]+sizeof(ref_buf); p1++ )
	{
		avg += *p1;
	}
	avg /= sizeof(ref_buf);

	avg_ref_intensity = (unsigned char)avg;
}

void calculate_histogram(int vid_width,int vid_height )
{
  int x,y,max=0,value;
  
  unsigned char tval;
  
  for (x=0;x<255;x++)
    histogram[x]=0;

  for (y=0;y<vid_height;y++)
  {
    for (x=0;x<vid_width;x++)
    {
      tval=gray_1b[(y*vid_width)+(x)];
      histogram[tval]++;
    }
  }
  memset(hist_buf,0,sizeof(hist_buf));
  for (x=0;x<255;x++)
  {
    if (max<histogram[x])
      max=histogram[x];
  }
  for (x=0;x<255;x++)
  {
    value=ceil((histogram[x]*50)/max);
    if (x==0){
      for (y=50;y>0;y--)
      {
        hist_buf[(y*vid_width*3)+(x*3)+0]=255;
        hist_buf[(y*vid_width*3)+(x*3)+1]=255;
        hist_buf[(y*vid_width*3)+(x*3)+2]=255;
      }
    }
    else
    if (x==254){
      for (y=50;y>0;y--)
      {
        hist_buf[(y*vid_width*3)+(x*3)+0]=255;
        hist_buf[(y*vid_width*3)+(x*3)+1]=255;
        hist_buf[(y*vid_width*3)+(x*3)+2]=255;
      }
    }
    else
      for (y=50;y>(50-value);y--)
      {
        hist_buf[(y*vid_width*3)+(x*3)+0]=255;
        hist_buf[(y*vid_width*3)+(x*3)+1]=255;
        hist_buf[(y*vid_width*3)+(x*3)+2]=0;
      }    
  }
}

void one_2_tree_bytes(int vid_width,int vid_height,char *in_pic,char *out_pic)
{
  int x,y;
  int tval;
  
  
  for (y=0;y<vid_height;y++)
  {
    for (x=0;x<vid_width;x++)
    {
      tval=in_pic[(y*vid_width)+(x)];
      out_pic[(y*vid_width*3)+(x*3)+0]=tval;
      out_pic[(y*vid_width*3)+(x*3)+1]=tval;
      out_pic[(y*vid_width*3)+(x*3)+2]=tval;
    }
  }
}