package video; import java.io.IOException; import java.io.InputStream; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.media.Manager; import javax.microedition.media.MediaException; import javax.microedition.media.Player; import javax.microedition.media.PlayerListener; import javax.microedition.media.control.VideoControl; public class MIDPPixelSource implements VideoListener, Runnable, PlayerListener { Player p; VideoControl vc; int imageWidth; int imageHeight; byte[] imageBytes; // compressed image as bytes int[] imagePixels; // uncompressed image as bytes VideoListener listener; int interval = 66; Thread tickler; boolean fakeVideo; byte[] fakeVideoPngArray; Image fakeVideoImage; Graphics fakeVideoGraphics; int xDir = 1; int yDir = 1; int x = 0; int y = 0; String encoding = "png"; Canvas displayCanvas; /** * Creates a connect to the camera for getting images and pixels. If video capture is not available, a fake video screen with a bouncing ball will appear. * * @param _w * width the image * @param _h * height of the image */ public MIDPPixelSource(int _w, int _h) { imageWidth = _w; imageHeight = _h; startVideo("capture://video", null); } /** * Creates a connect to the camera for getting images and pixels. This will not even check for the availability of video capture but will go directly to the fake video. * * @param _w * width the image * @param _h * height of the image */ public MIDPPixelSource(int _w, int _h, boolean _fakeVideo) { // http://developers.sun.com/techtopics/mobility/midp/articles/mmapioverview/ imageWidth = _w; imageHeight = _h; fakeIt(); // myImage = Image.createImage(fakeVideoPngArray,0, fakeVideoPngArray.length); } /** * Creates a connect to a video for getting images and pixels. * * @param _w * width the image * @param _h * height of the image * @param _url * the address of the video. could be "capture://video" for the camera * or http://bla bal for a video. * @param _canvas * for faster rendering to the screen you can supply a canvas that will * automatically get video put on it. I don't think you get much control after that. * * */ public MIDPPixelSource(int _w, int _h, String _url, Canvas _canvas) { // http://developers.sun.com/techtopics/mobility/midp/articles/mmapioverview/ imageWidth = _w; imageHeight = _h; displayCanvas = _canvas; startVideo(_url, _canvas); setDimensions(_w,_h); } public void fakeIt() { fakeVideo = true; System.out.println("Fake The Video"); //try { InputStream is = this.getClass().getResourceAsStream("/fakeVideo.png"); try{ fakeVideoPngArray = new byte[is.available()]; is.read(fakeVideoPngArray); } catch (Exception e) { System.out.println("Problem finding fakeVideo.png put a 160 x 120 .png file named \"fakeVideo.png\" in your resource directory or in the root of your project directory"); } fakeVideoImage = Image.createImage(imageWidth, imageHeight); fakeVideoGraphics = fakeVideoImage.getGraphics(); addVideoListener(this, 30); } void startVideo(String _url, Canvas _canvas) { if (_url == null) _url = "capture://video"; System.out.println("Looking for: " + _url); boolean isCaptureURL = _url.indexOf("capture:") != -1; String canCapture = System.getProperty("supports.video.capture"); if (isCaptureURL && canCapture != null && canCapture.toLowerCase().indexOf("false") != -1) { fakeIt(); } else { try { p = Manager.createPlayer(_url); p.prefetch(); p.realize(); p.addPlayerListener(this); //if (isCaptureURL) p.start(); vc = (VideoControl) p.getControl("VideoControl"); if (_canvas != null) { vc.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, _canvas); vc.setVisible(true); System.out.println("Direct to Canvas"); } else { vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null); //vc.setVisible(true); System.out.println("Not Direct to Canvas"); } } catch (IOException e) { System.out.println("problem with url " + _url); } catch (MediaException e) { System.out.println("I guess you can't capture"); fakeIt(); } } } public void setLocationOnCanvas(int _x, int _y){ if (vc != null){ vc.setDisplayLocation(_x, _y); } } public void playerUpdate(Player arg0, String arg1, Object arg2) { System.out.println("event " + arg1 + " " + arg2); try { p.start(); } catch (MediaException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Gets the image from the camera. * * @return an array of bytes compressed as a png */ public byte[] grabFrame() { if (fakeVideo) { return imageBytes; } imageBytes = null; try { //imageBytes = vc.getSnapshot( null); imageBytes = vc.getSnapshot("encoding=" + encoding + "&width=" + imageWidth + "&height=" + imageHeight); // imageBytes = vc.getSnapshot("encoding=png&width=" + imageWidth + "&height=" + imageHeight); } catch (MediaException e) { e.printStackTrace(); } return imageBytes; } public void newFrame(){ fakeVideoGraphics.setColor(0); fakeVideoGraphics.fillRect(0, 0, imageWidth, imageHeight); fakeVideoGraphics.setColor(150); if (x >= imageWidth) xDir = -xDir; if (y >= imageHeight) yDir = -yDir; if (x < 0) xDir = -xDir; if (y < 0) yDir = -yDir; x = x + xDir; y = y + yDir; fakeVideoGraphics.fillRect(x, y, 10, 10); fakeVideoGraphics.setColor(255); fakeVideoGraphics.drawString("Fake Video", 10, 10, 0); fakeVideoGraphics.drawString(String.valueOf(System.currentTimeMillis()), 10, 30, 0); displayCanvas.repaint(); } /** * Change the resolution that you are grabbing at * * @param _w * @param _h */ public void setDimensions(int _w, int _h) { imageWidth = _w; imageHeight = _h; if (vc != null){ try { vc.setDisplaySize(_w, _h); } catch (MediaException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Change an image into an array of ints. * * @param _image * @return Each int in the array contains RGB and potentially alpha if "unpacked" for one pixel */ public int[] getPixelArray(Image _image) { if (_image == null) _image = getImage(); imagePixels = new int[imageWidth * imageHeight]; _image.getRGB(imagePixels, 0, imageWidth, 0, 0, imageWidth, imageHeight); return imagePixels; } /** * Gives you back the bytes of the most recent image as a compressed png. * * @return */ public byte[] getImageBytes() { if (fakeVideo) { if (fakeVideoPngArray == null){ System.out.println("Problem finding fakeVideo.png put a 160 x 120 .png file named \"fakeVideo.png\" in your resource directory or in the root of your project directory"); return null; }else{ imageBytes = fakeVideoPngArray; return imageBytes; } } return imageBytes; } /** * Gives your the brightness of the a pixel at a given location of the most recently grabbed frame. * * @param _col * @param _row * @return 0-255; */ public int[] getBrightness(int _col, int _row) { int[] rgb = new int[4]; int offset = _row * imageWidth + _col; rgb[0] = offset; int thisPixel = imagePixels[offset]; // 0xAARRGGBB rgb[1] = (byte) ((thisPixel & 0x000000ff) & 0xff); return rgb; } /** * Gives you back the Red Green and Blue of a pixel at the specified location of the most recent frame. * * @param _col * @param _row * @return 4 elements, 0 element is offset in the array, 1 is the red, 2, is the green, 3 is the blue */ public int[] getPixel(int _col, int _row) { int[] rgb = new int[4]; int offset = _row * imageWidth + _col; rgb[0] = offset; int thisPixel = imagePixels[offset]; // 0xAARRGGBB rgb[1] = (byte) ((thisPixel & 0x000000ff) & 0xff); rgb[2] = (byte) (((thisPixel >>> 8) & 0xff) & 0xff); rgb[3] = (byte) (((thisPixel >>> 16) & 0xff) & 0xff); return rgb; } /** * Gives you back the Red Green and Blue of a pixel at the specified location in the supplied pixel array. * * @param _col * @param _row * @return 4 elements, 0 element is offset in the array, 1 is the red, 2, is the green, 3 is the blue */ public int[] getPixel(int _offset, int[] _imagePixels) { int[] rgb = new int[4]; int thisPixel = _imagePixels[_offset]; // 0xAARRGGBB rgb[1] = (byte) ((thisPixel & 0x000000ff) & 0xff); rgb[2] = (byte) (((thisPixel >>> 8) & 0xff) & 0xff); rgb[3] = (byte) (((thisPixel >>> 16) & 0xff) & 0xff); return rgb; } /** * Give the image of the most recent frame. * * @return */ public Image getImage() { Image myImage = null; if (fakeVideo) { return fakeVideoImage; }else if (displayCanvas == null){ try { myImage = Image.createImage(imageBytes, 0, imageBytes.length); } catch (SecurityException e2) { System.out.println("Security Issue" + e2); } catch (OutOfMemoryError e) { System.out.println("Memory Trouble" + e); } return myImage; }else{ return null; } } /** * This will make the pixelsource notify you when a new frame is ready. You have to have made your other class a "VideoListener" by implementing "VideoListener." You also have to have put in a "newFrame()" function in the other class. * * @param _videoListener * This the class that has the "newFrame" method in it that gets notified. * @param _frameRate * */ public void addVideoListener(VideoListener _videoListener, int _frameRate) { interval = 1000 / _frameRate; listener = _videoListener; tickler = new Thread(this); tickler.start(); } public void run() { while (true) { grabFrame(); if (listener != null) { listener.newFrame(); } try { Thread.sleep(interval); } catch (InterruptedException e) { } } } /** * Give you the latest array of uncompressed image pixels. * * @return */ public int[] getImagePixels() { return imagePixels; } public void setImagePixels(int[] imagePixels) { this.imagePixels = imagePixels; } public int getImageWidth() { return imageWidth; } public int getImageHeight() { return imageHeight; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } }