import javax.media.*; import javax.media.format.*; import java.awt.*; public class MovementEffect implements Effect { Format inputFormat; Format outputFormat; Format[] inputFormats; Format[] outputFormats; private Control[] controls; String[] mail_list = new String[10]; boolean alert_mode = false; int full_red_blocks; int num_frames_processed = 0; int num_frames_high = 0; float percent_high = 0.5f; int blocksize = 2; int new_block_size; boolean change_wanted = false; int numofblocks; int katofli_a = 85; int katofli_b = 55; int katofli_c = 28; boolean start = true; boolean one_frame_mode = false; double n_1_frame = 0.8; double n_2_frame = 0.2; int choose; byte[] prevframe1; byte[] prevframe2; byte[] ref_scaled; byte[] ref_luminance; byte[] cur_scaled; byte[] cur_luminance; byte[] dif_scaled; RGBFormat vfIn; // Borrowed from Sun's JMF Examples public MovementEffect() { inputFormats = new Format [] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 3, 2, 1, 3, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) }; outputFormats = new Format[] { new RGBFormat(null, Format.NOT_SPECIFIED, Format.byteArray, Format.NOT_SPECIFIED, 24, 3, 2, 1, 3, Format.NOT_SPECIFIED, Format.TRUE, Format.NOT_SPECIFIED) }; } public int process(Buffer inBuffer, Buffer outBuffer) { int block_dif; full_red_blocks = 0 ; //new frame started, we don't know if there is any movement num_frames_processed++; if (num_frames_processed == 13500) { //15 minutes supposing 15 fps num_frames_processed = 0; num_frames_high = 0; } if (change_wanted == true) { //changing block_size, implementation similiar to semaphores set_blocksize(); change_wanted = false; } int outputDataLength = ( (VideoFormat) outputFormat).getMaxDataLength(); validateByteArraySize(outBuffer, outputDataLength); outBuffer.setLength(outputDataLength); outBuffer.setFormat(outputFormat); outBuffer.setFlags(inBuffer.getFlags()); byte[] inData = (byte[]) inBuffer.getData(); byte[] outData = (byte[]) outBuffer.getData(); vfIn = (RGBFormat) outputFormat; //Copy all data from the inbuffer to the outbuffer. The purpose is to display the video input on the screen. System.arraycopy(inData, 0, outData, 0, outData.length); numofblocks = (int) (Math.ceil( (float) outputDataLength / (float) (3 * (blocksize * blocksize)))); if (start == true) { if (one_frame_mode == true) { //*********** using 1 frame for reference frame *************************** ref_luminance = rgb2yuv(inData); //ref_luminance = rgb2bw(inData); // ref_scaled = scale_down(ref_luminance); //************************************************************************* } else { //****** using average values of 2 frames for reference frame ************* // prevframe1 = new byte[numofblocks]; prevframe2 = new byte[numofblocks]; prevframe1 = scale_down(rgb2yuv(inData)); // prevframe1 = scale_down(rgb2bw(inData)); System.arraycopy(prevframe1, 0, prevframe2, 0, prevframe1.length); choose = 1; // either 1 or 2 does the job ref_scaled = average(prevframe1, prevframe2, choose); //************************************************************************* } start = false; } else { cur_luminance = rgb2yuv(inData); //cur_luminance = rgb2bw(inData); dif_scaled = new byte[numofblocks]; cur_scaled = scale_down(cur_luminance); for (int i = 0; i < numofblocks; i++) { dif_scaled[i] = (byte) Math.abs( ( (int) cur_scaled[i] & 0xFF) - ( (int) ref_scaled[i] & 0xFF)); block_dif = ( ( (int) dif_scaled[i] & 0XFF)); if (block_dif > katofli_a) { //high movement mark_movement(outData, i, 255, 0, 0); full_red_blocks++; } else if (block_dif > katofli_b) { //medium movement mark_movement(outData, i, 255, 150, 150); } else if (block_dif > katofli_c) { //low movement mark_movement(outData, i, 255, 235, 235); } } //for //System.out.println("Moving blocks:" + move +"\nNon moving blocks:"+ nomove); if (one_frame_mode == true) { //*********** using 1 frame for reference frame *************************** ref_scaled = cur_scaled; //using 1 frame for reference frame*/ //************************************************************************* } else { //****** using average values of 2 frames for reference frame ************* if (choose == 1) { prevframe2 = cur_scaled; choose = 2; } else { prevframe1 = cur_scaled; choose = 1; } ref_scaled = average(prevframe1, prevframe2, choose); //************************************************************************* } } //else if (full_red_blocks> (numofblocks/20) ) num_frames_high++; //5% of frames if ( ( (float) num_frames_high / 13500) > percent_high) { if ( (mail_list[0] != null) && (mail_list[0] != "") && (mail_list[0].indexOf("@") != -1) && alert_mode ) { MovementDetect.send_the_mail(mail_list); } num_frames_high = 0; num_frames_processed = 0; } // System.out.println("Alert mode:"+ alert_mode + "\nNum_frames_high:" + num_frames_high + "\nnum_frames_processed:" +num_frames_processed + "\nMail list:" + mail_list[0] + "\nPercent high" + percent_high + "\nFull Red Blocks" + full_red_blocks); return BUFFER_PROCESSED_OK; } byte[] average(byte[] prevframe1, byte[] prevframe2, int choose) { double percent1, percent2; byte[] output = new byte[prevframe1.length]; if (choose == 1) { percent1 = n_1_frame; percent2 = n_2_frame; } else { percent1 = n_1_frame; percent2 = n_2_frame; } // System.out.println(n_1_frame+ ":"+n_2_frame); for (int i = 0; i < prevframe1.length; i++) { output[i] = (byte) ( ( (int) prevframe1[i] & 0xFF) * percent1 + ( (int) prevframe2[i] & 0xFF) * percent2); } return output; } void mark_movement(byte[] outData, int index, int r, int g, int b) { Dimension sizeIn = vfIn.getSize(); int iw = sizeIn.width; int ih = sizeIn.height; int scaled_iw = (int) Math.ceil( ( (float) iw / (blocksize))); int scaled_ih = (int) Math.ceil( (double) (ih / (blocksize))); int block_i, block_j, current; block_i = index / scaled_iw; block_j = index - block_i * scaled_iw; current = (iw * blocksize * block_i + blocksize * block_j); for (int row = 0; row < blocksize; row++) { for (int col = 0; col < blocksize; col++) { outData[ (current + col) * 3] = ( (byte) b); outData[ (current + col) * 3 + 1] = ( (byte) g); outData[ (current + col) * 3 + 2] = ( (byte) r); } current += iw; } } byte[] scale_down(byte[] input) { Dimension sizeIn = vfIn.getSize(); int iw = sizeIn.width; int ih = sizeIn.height; int scaled_iw = (int) Math.ceil( ( (float) iw / (blocksize))); //int scaled_ih = (int) Math.ceil( (double)(ih / (blocksize )) ); byte[] output = new byte[numofblocks]; int[] scale_sum = new int[numofblocks]; int[] count = new int[numofblocks]; int row, col, block_i, block_j, index; for (int i = 0; i < input.length; i++) { row = i / iw; col = i - row * iw; block_i = row / blocksize; block_j = col / blocksize; index = block_i * scaled_iw + block_j; scale_sum[index] = ( (int) input[i] & 0xFF) + scale_sum[index]; count[index] += 1; } for (int k = 0; k < numofblocks; k++) { if (scale_sum[k] < 0) { System.out.println(k); //all blocks must be positive } if (count[k] > 0) { output[k] = (byte) (scale_sum[k] / count[k]); } } return (output); } byte[] rgb2bw(byte[] rgb_array) { byte[] bw_array = new byte[rgb_array.length / 3]; for (int i = 0; i < rgb_array.length; i = i + 3) { bw_array[i / 3] = (byte) ( ( ( (int) rgb_array[i] & 0xFF) + ( (int) rgb_array[i + 1] & 0xFF) + ( (int) rgb_array[i + 2] & 0xFF)) / 3); } return bw_array; } byte[] rgb2yuv(byte[] rgb_array) { byte[] y_array = new byte[rgb_array.length / 3]; for (int i = 0; i < rgb_array.length; i = i + 3) { y_array[i / 3] = (byte) (0.299 * ( (int) rgb_array[i] & 0xFF) + 0.587 * ( (int) rgb_array[i + 1] & 0xFF) + 0.114 * ( (int) rgb_array[i + 2] & 0xFF)); } return y_array; } public void set_blocksize() { blocksize = new_block_size; start = true; } public void set_frame_mode(boolean value) { one_frame_mode = value; start = true; } public void set_all_limits(int high, int medium, int low) { katofli_a = high; katofli_b = medium; katofli_c = low; } public void set_frames_percentage(double n_1, double n_2) { n_1_frame = n_1; n_2_frame = n_2; } // Borrowed from Sun's JMF Examples byte[] validateByteArraySize(Buffer buffer, int newSize) { Object objectArray = buffer.getData(); byte[] typedArray; if (objectArray instanceof byte[]) { // Has correct type and is not null typedArray = (byte[]) objectArray; if (typedArray.length >= newSize) { // Has sufficient capacity return typedArray; } byte[] tempArray = new byte[newSize]; // Reallocate array System.arraycopy(typedArray, 0, tempArray, 0, typedArray.length); typedArray = tempArray; } else { typedArray = new byte[newSize]; } buffer.setData(typedArray); return typedArray; } // Borrowed from Sun's JMF Examples public void open() { } // Borrowed from Sun's JMF Examples public void close() { } // Borrowed from Sun's JMF Examples public void reset() { } // Borrowed from Sun's JMF Examples public Object getControl(String controlType) { return null; } // Borrowed from Sun's JMF Examples public Object[] getControls() { return null; } // Borrowed from Sun's JMF Examples public String getName() { return "Movement Detection Implementation"; } // Borrowed from Sun's JMF Examples public Format[] getSupportedInputFormats() { return inputFormats; } // Borrowed from Sun's JMF Examples public Format setInputFormat(Format input) { inputFormat = input; return input; } // Borrowed from Sun's JMF Examples public Format[] getSupportedOutputFormats(Format input) { if (input == null) { return outputFormats; } if (matches(input, inputFormats) != null) { return new Format[] { outputFormats[0].intersects(input)}; } else { return new Format[0]; } } // Borrowed from Sun's JMF Examples public Format setOutputFormat(Format output) { if (output == null || matches(output, outputFormats) == null) { return null; } RGBFormat incoming = (RGBFormat) output; Dimension size = incoming.getSize(); int maxDataLength = incoming.getMaxDataLength(); int lineStride = incoming.getLineStride(); float frameRate = incoming.getFrameRate(); int flipped = incoming.getFlipped(); int endian = incoming.getEndian(); if (size == null) { return null; } if (maxDataLength < size.width * size.height * 3) { maxDataLength = size.width * size.height * 3; } if (lineStride < size.width * 3) { lineStride = size.width * 3; } if (flipped != Format.FALSE) { flipped = Format.FALSE; } outputFormat = outputFormats[0].intersects(new RGBFormat(size, maxDataLength, null, frameRate, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED, lineStride, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED)); return outputFormat; } // // Borrowed from Sun's JMF Examples Format matches(Format in, Format outs[]) { for (int i = 0; i < outs.length; i++) { if (in.matches(outs[i])) { return outs[i]; } } return null; } }