#!/usr/bin/python
# Downloads JPEG images from ALLNET ALL2281 WLAN Camera
# Only saves images if something moves.
# Config file has to look like this: 
# { 'url' : 'http://www.server.com/axis-cgi/mjpg/video.cgi' }
# Threshold will be determined on first run.

import sys,time,os
config_fn=sys.argv[1]
cfg=eval(open(config_fn).read())
cam_id=os.path.splitext(os.path.basename(config_fn))[0]
out_dir='%s/watchrat/%s' % (os.environ['HOME'],cam_id)
if not os.path.isdir(out_dir): 
 os.mkdir(out_dir)
 print 'Created direcory %s' % out_dir
if not cfg.has_key('default_read'): cfg['default_read']=50000
if not cfg.has_key('step'): cfg['step']=5
if not cfg.has_key('min_size'): cfg['min_size']=6000
if not cfg.has_key('delay'): cfg['delay']=0.5

def getMJPG(url,readLength=cfg['default_read'],multiple=False):
 import urllib,sys,exceptions
 try: stream=urllib.urlopen(url).read(readLength)
 except exceptions.KeyboardInterrupt: raise
 except:
  print sys.exc_info()[1]
  return getMJPG(url,readLength=readLength)
 if multiple: return stream
 header=stream.split('\r\n\r\n')[0]
 if 'Length: ' not in header:
  print 'Bad MJPEG header'
  return getMJPG(url,readLength=readLength)
 content_length=int(header.split('Length: ')[1])
 if content_length>readLength: return getMJPG(url,readLength=readLength*2)
 data_start=len(header)+4
 return stream[data_start:(data_start+content_length)]

def compare_images(jpeg1,jpeg2):
 import Image,StringIO,exceptions
 i1, i2=Image.open(StringIO.StringIO(jpeg1)), Image.open(StringIO.StringIO(jpeg2))
 try: pix1, pix2 = i1.load(), i2.load()
 except exceptions.KeyboardInterrupt: raise
 except: return 0
 total=0
 for i in range(0,i1.size[0],cfg['step']):
  for j in range(0,i1.size[1],cfg['step']): 
   total+=sum(map(lambda c1,c2 : abs(c1-c2),pix1[i,j],pix2[i,j]))
 area=i1.size[0]/cfg['step']*i1.size[1]/cfg['step']
 return total/3/area

def wait(s):
 time.sleep(cfg['delay'])
 return s

def save_file(x):
 ofn='%s/%s%d.jpg' % (out_dir,cam_id,int(time.time()*100))
 open(ofn,'w').write(x)

def check_config(cfg):
 assert cfg.has_key('url')
 if len(cfg.keys())==6: return cfg
 import numpy
 sample_size=100
 diffs,sizes,last=[],[],False
 for i in range(sample_size):
  jpeg=getMJPG(cfg['url'])
  sizes.append(len(jpeg))
  if last: 
   diff=compare_images(last,jpeg)
   diffs.append(diff)
   open('%s/test%03d.jpg' % (out_dir,i),'w').write(jpeg)
   print '%s %d / %d: %d byte written, diff = %d' % (cam_id,i,sample_size,len(jpeg),diff)
  last=jpeg
 nt=int(numpy.mean(diffs)*2)+1
 if nt<4: nt=4
 cfg['threshold']=nt
 cfg['default_read']=max(sizes)
 if cfg['min_size']>min(sizes): cfg['min_size']=min(sizes)/2
 open(config_fn,'w').write(str(cfg))
 return cfg

cfg=check_config(cfg)
last,on,zero_count,c1,c2=False,False,0,0,0
while True:
 jpeg=getMJPG(cfg['url'])
 if len(jpeg)<cfg['min_size']: 
  last=jpeg
  print wait( '%s: %d byte of darkness, checked = %d, saved = %s' % (cam_id,len(jpeg),c1,c2) )
  on=False
  continue
 if last:
  if len(jpeg)==len(last): 
   last=jpeg
   print wait( '%s: size identical, checked = %d, saved = %s' % (cam_id,c1,c2) )
   continue
  c1+=1
  d=compare_images(last,jpeg)
  if d>cfg['threshold']: on=True
  if d<=cfg['threshold']/2: zero_count+=1
  else: zero_count=0
  if zero_count>=1: on=False # was 3 (1 = no capture without event)
 if on: 
  save_file(jpeg)
  tp=cam_id,len(jpeg),d,cfg['threshold'],zero_count,c1,c2
  print '%s: w.byte = %d, dif = %d, thr = %d, wait = %d, check = %d, save = %d' % tp
  c2+=1
 elif last: 
  tp=cam_id,len(jpeg),d,cfg['threshold'],c1,c2
  print wait( '%s: size = %d, diff = %d, thresh = %d, check = %s, save = %s' % tp)
 last=jpeg