/**
	Title: VideoByPixelJMF
	Author: Shawn Van Every
	Description: Using JMF to Capture and Analyze Video Frames
	Usage: Anything goes...  I like to see other people's projects, feel free to point me to yours.
	Note:  This could use some optimization, 
	if you do some optimization please send me an email: vanevery@yahoo.com
 */

import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.io.*;

import javax.media.*;
import javax.media.format.*;
import javax.media.util.*;
import javax.media.control.*;
import javax.media.protocol.*;

public class VideoByPixelJMF extends JApplet {
	public void init() {
		try {
			VideoByPixelJMFFrame frame = new VideoByPixelJMFFrame();
			frame.initComponents();
			frame.setVisible(true);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	// Main entry point
	static public void main(String[] args) {
		VideoByPixelJMF vbp = new VideoByPixelJMF();
		vbp.init();
	}
}


class VideoByPixelJMFFrame extends javax.swing.JFrame {
	// Outer window setup
	protected JWindow outerWindow = new JWindow();
	Dimension screenSize;
	boolean frameHidden = false;

	// JMF Setup
	public static Player mediaPlayer = null;
	public CaptureDeviceInfo captureDeviceInfo = null;
	public MediaLocator mediaLocator = null;
	public BufferToImage bufferToImage = null;
	public Buffer imageBuffer = null;

	public VideoFormat videoFormat = null;

	// User Defined Vars (Should be constants)
	int frameHeight = 480;
	int frameWidth = 640;
	int framesPerSecond = 15;
	int playTimerDelay = 1000/framesPerSecond;
	int imageScanSkip = 5;

	// Video Stream Vars
	int videoWidth;
	int videoHeight;

	int dataLength;
	int dataOffset;
	int theData[];

	FrameGrabbingControl frameGrabbingControl;

	// UI Objects
	javax.swing.JMenuBar menuBar = new javax.swing.JMenuBar();
	javax.swing.JMenu processMenu = new javax.swing.JMenu();
	javax.swing.JMenuItem processMenuStart = new javax.swing.JMenuItem();
	javax.swing.JMenuItem processMenuStop = new javax.swing.JMenuItem();

	private javax.swing.Timer playTimer;

	// Default Constructor
	public VideoByPixelJMFFrame() {
	}

	public void initComponents() throws Exception
	{
		// Frame initialization
		screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		setSize(new java.awt.Dimension(frameWidth,frameHeight));
		setLocation((screenSize.width - frameWidth)/2,(screenSize.height - frameHeight)/2);
		setResizable(false);
		setTitle("Video By Pixel");

		// Component initialzation
		menuBar.setVisible(true);

		processMenu.setVisible(true);
		processMenu.setText("Process Video");
		processMenuStart.setVisible(true);
		processMenuStart.setText("Start");
		processMenuStop.setVisible(true);
		processMenuStop.setText("Stop");
		setJMenuBar(menuBar);
		
		// Add the components
		menuBar.add(processMenu);
		processMenu.add(processMenuStart);
		processMenu.add(processMenuStop);

		// JMF Initialization
		// Locate and aquire the capture device
		Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, new Boolean(true));
		String captureDeviceStr = "vfw:Microsoft WDM Image Capture (Win32):0";
		captureDeviceInfo = CaptureDeviceManager.getDevice(captureDeviceStr);
		mediaLocator = captureDeviceInfo.getLocator();
		
		try
		{
			mediaPlayer = Manager.createRealizedPlayer(mediaLocator);			
			mediaPlayer.start();
			Component playerComponent;

			if ((playerComponent = mediaPlayer.getVisualComponent()) != null)
			{
				getContentPane().add(playerComponent);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		setDefaultCloseOperation(EXIT_ON_CLOSE);

		// Setup playTimer
		playTimer = new javax.swing.Timer(playTimerDelay, new
			ActionListener()
			{
				public void actionPerformed(ActionEvent Event)
				{
					playNextImage();
				}
			});

		// UI event handling
		processMenuStart.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				
				frameGrabbingControl = (FrameGrabbingControl) mediaPlayer.getControl("javax.media.control.FrameGrabbingControl");
				
				// Grab a frame for video size calibration
				imageBuffer = frameGrabbingControl.grabFrame();
		
				dataLength = imageBuffer.getLength();
				dataOffset = imageBuffer.getOffset();
		
				dataLength = dataLength - dataOffset;
				int dataLengthDivisor = frameHeight * frameWidth / dataLength;
				videoHeight = frameHeight / dataLengthDivisor;
				videoWidth = frameWidth / dataLengthDivisor;
				
				playTimer.start();
			}
		});

		processMenuStop.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				playTimer.stop();
			}
		});
	}


	private void playNextImage()
	{
		//System.out.println("analyzing frame");
		
		// Pixel Data
		int redPixel, greenPixel, bluePixel;
		
		// Grab a frame
		imageBuffer = frameGrabbingControl.grabFrame();

		theData = new int[dataLength];

		/*
		if (imageBuffer.getData() instanceof byte[])
		{
			System.out.println("Instance of byte[]");
		}
		else if (imageBuffer.getData() instanceof int[])
		{
		*/
                	theData = (int[]) imageBuffer.getData();
                /*}*/

                // Do left math
                for (int y = 0; y < videoHeight - imageScanSkip; y+=imageScanSkip) {
                        for (int x = 1; x < videoWidth - imageScanSkip; x+=imageScanSkip)
                        {
                                bluePixel = (	theData[y*videoWidth+x]	     )	& 0xff;
                                greenPixel = (	theData[y*videoWidth+x]	>> 8 ) 	& 0xff;
                                redPixel = (	theData[y*videoWidth+x] >> 16) 	& 0xff;
                                
				// Do your analysis here
                        }
                }
	}
}