193 lines
6.1 KiB
HTML
193 lines
6.1 KiB
HTML
<html>
|
|
<head>
|
|
<title>MJPEG-Streamer</title>
|
|
|
|
<!-- refresh page after a few seconds, prevents hang-ups -->
|
|
<meta http-equiv="refresh" content="60" />
|
|
</head>
|
|
|
|
<script language="javascript" type="text/javascript" src="functions.js"></script>
|
|
<script type="text/javascript">
|
|
|
|
/*******************************************************************************
|
|
Copyright (C) 2009 Tom Stoeveken
|
|
This program is free software;
|
|
you can redistribute it and/or modify it under the terms of the
|
|
GNU General Public License, version 2.
|
|
See the file COPYING for details.
|
|
*******************************************************************************/
|
|
|
|
var img1 = null;
|
|
var img2 = null;
|
|
var canvas = null;
|
|
|
|
/*
|
|
compare two images and count the differences
|
|
|
|
input.: image1 and image2 are Image() objects
|
|
input.: canvas is a Canvas() object to draw with
|
|
input.: threshold specifies by how much the color value of a pixel
|
|
must differ before they are regarded to be different
|
|
|
|
return: number of different pixels
|
|
*/
|
|
function compare(image1, image2, canvas, threshold) {
|
|
var movement = 0;
|
|
var ctx = canvas.getContext("2d");
|
|
var width = canvas.width/2, height = canvas.height/2;
|
|
|
|
// copy images into canvas element
|
|
// these steps scale the images and decodes the image data
|
|
ctx.drawImage(image1, 0, 0, width, height);
|
|
ctx.drawImage(image2, width, 0, width, height);
|
|
|
|
// this makes r,g,b,alpha data of images available
|
|
var pixels1 = ctx.getImageData(0, 0, width, height);
|
|
var pixels2 = ctx.getImageData(width, 0, width, height);
|
|
var pixels_diff = ctx.getImageData(0, 0, width, height);
|
|
|
|
// substract picture1 from picture2
|
|
// if they differ set color value to max,
|
|
// if the difference is below threshold set difference to 0.
|
|
for (var x = 0; x < pixels1.width; x++) {
|
|
for (var y = 0; y < pixels1.height; y++) {
|
|
|
|
// each pixel has a red, green, blue and alpha value
|
|
// all values are stored in a linear array
|
|
var i = x*4 + y*4*pixels1.width;
|
|
|
|
pixels_diff.data[i] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
|
|
pixels_diff.data[i+1] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
|
|
pixels_diff.data[i+2] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
|
|
pixels_diff.data[i+3] = 255;
|
|
|
|
// count differing pixels
|
|
movement += Math.min(1, pixels_diff.data[i] + pixels_diff.data[i+1] + pixels_diff.data[i+2]);
|
|
}
|
|
}
|
|
|
|
ctx.putImageData(pixels_diff, width/2, height);
|
|
|
|
return movement;
|
|
}
|
|
|
|
/*
|
|
Callback function for completed picture downloads
|
|
|
|
With every new picture a compare() is performed.
|
|
The new picture is 'img1', the previous picture is stored in 'img2'.
|
|
*/
|
|
function newPictureComplete() {
|
|
// just compare if there are two pictures
|
|
if ( img2 != null ) {
|
|
var res;
|
|
|
|
try {
|
|
// compare the two pictures, the given threshold helps to ignore noise
|
|
res = compare(img1, img2, canvas, 50);
|
|
}
|
|
catch(e) {
|
|
// errors can happen if the pictures were corrupted during transfer
|
|
// instead of giving up, just proceed
|
|
}
|
|
|
|
// show to the user if we regards this as motion
|
|
// decide for a color depending on movement (more then N pixels)
|
|
// draw into free area of canvas
|
|
// (hardcoded positions for better performance)
|
|
var ctx = canvas.getContext("2d");
|
|
ctx.fillStyle = ( res > 5 ) ? "rgb(200,0,0)" : "rgb(0,200,0)";
|
|
ctx.fillRect (0, 50, 25, 50); ctx.fillRect (75, 50, 25, 50);
|
|
|
|
// send server our finding that there was some movement
|
|
if ( res > 5 ) {
|
|
AJAX_get('./?action=command&command=store')
|
|
}
|
|
}
|
|
|
|
// copy reference of img1 to img2
|
|
img2 = img1;
|
|
img2.onload = null;
|
|
// load a new picture into img1
|
|
img1 = new Image();
|
|
img1.onload=newPictureComplete;
|
|
|
|
// load next picture in a few milliseconds
|
|
// the server blocks anyway until a fresh picture has arrived, so it can never be faster
|
|
// than the framerate. This timeout is intended to have the option
|
|
// to lower the required processing power at client side.
|
|
window.setTimeout("img1.src='./?action=snapshot&unique='+Math.random();", 1);
|
|
}
|
|
|
|
/*
|
|
Initialize the elements
|
|
|
|
* Create a Canvas() object and insert it into the page
|
|
* Download the first image
|
|
* Pause the Livestream again if we were paused previously
|
|
This way we will not pause, but we will lower the refresh rate
|
|
For a proper pause, the page can not be reloaded
|
|
*/
|
|
function run() {
|
|
canvas = document.createElement("canvas");
|
|
canvas.width = 100;
|
|
canvas.height = 100;
|
|
canvas.id = "comparison_canvas";
|
|
document.getElementById("comparison").appendChild(canvas);
|
|
|
|
img1 = new Image();
|
|
img1.onload=newPictureComplete;
|
|
img1.src = "./?action=snapshot";
|
|
|
|
if ( window.name.indexOf('paused') != -1 )
|
|
play_pause(document.getElementById("stream"));
|
|
}
|
|
|
|
/*
|
|
Callback function for AJAX command
|
|
|
|
input.: text is the response of the server
|
|
*/
|
|
function AJAX_response(text) {
|
|
// nothing to do
|
|
// later we might show a little folder symbol or so that dissapears
|
|
// after a while
|
|
}
|
|
|
|
/*
|
|
can toggle play/pause of the HTTP-push live preview
|
|
|
|
input.: 'img' is the Image() object displaying the stream/picture
|
|
*/
|
|
function play_pause(img) {
|
|
if ( img.src.indexOf('./?action=stream') != -1 ) {
|
|
img.src = "./?action=snapshot&unique="+Math.random();
|
|
|
|
// to keep the play/pause state over a page reload
|
|
// this persistent property of the window can be (mis)used
|
|
// it is a simple, but not so clean way of doing it
|
|
// a cookie or server side scripting would be better in order to
|
|
// pass information from one page to the other (reload)
|
|
window.name = 'paused';
|
|
} else {
|
|
img.src = "./?action=stream";
|
|
window.name = 'streaming';
|
|
}
|
|
}
|
|
|
|
</script>
|
|
<body onload="run()">
|
|
|
|
<fieldset style="background-color: silver; width: 200px; float: left">
|
|
<legend style="background-color: silver; border: 1px solid black">Motion Detection</legend>
|
|
<div id="comparison"></div>
|
|
</fieldset>
|
|
|
|
<fieldset style="background-color: silver; width: 50%">
|
|
<legend style="background-color: silver; border: 1px solid black">Lifestream</legend>
|
|
<img id="stream" src="./?action=stream" width="100%" onclick="play_pause(this)" />
|
|
</fieldset>
|
|
|
|
</body>
|
|
</html>
|