Java Media Framework vs IP Camera JPEG/MJPEG
NOTE:
+ This article is pretty deprecated. I do not say that the info here is false, but I would like to write a new article about this. Please leave me comments with what you want to know, and I will try do add more info to the article. And ofcourse, more sources.
+ A Romanian translation for this article is found here.
I really don”t think I”m either the first or the last to try and obtain images from and ip camera and than use them with JMF. So… after a few days of reading and trying to understand how JMF works, as I already had a JPEG/MJPEG grabber, here is my solutions:
As Chris Adamson explains in his article, Java Media Development with QuickTime for Java, to create a new JMF plugin you need to create two classes, one to extend DataSource and one to extend PushBufferStream or PullBufferStream from JMF. For DataSource I used PushBufferDataSource, which implements the parent class: DataSource.
The most important element is the fact that Datasource must be placed int a package named smth like this: name1.name2.someothername.media.protocol.numeprotocol (i.e. com.sun.media.protocol.http, com.sun.media.protocol.rtp, com.ibm.media.protocol.file).
For the DataSource class I used the example given by SUN in their ScreenGrabber, and I only modified the streaming class name. I won”t reveal the image grabing class, as SUN forum is allready filled with such examples, but I will reveal the streaming class under a surogated protocol I called htmjpeg. I”m sure it won”t take long to you to understant that the protocol is just a simple name, and can be easily changed in my example:
JMF MJPEG Plugin (for Download)
[[wppald_inposts|Donation for JMF Work]]
package com.itmc.media.protocol.htmjpeg; import com.itmc.ipcamera.mjpeg.grabber.mjpegGrabber; import java.awt.*; import java.awt.image.BufferedImage; import javax.media.*; import javax.media.format.*; import javax.media.protocol.*; import java.io.IOException; public class mjpegStream extends mjpegGrabber implements PushBufferStream, Runnable { protected ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW); protected int maxDataLength; protected int [] data; protected Dimension size; protected RGBFormat rgbFormat; protected boolean started; protected Thread thread; protected float frameRate = 7.0f; protected BufferTransferHandler transferHandler; protected Control [] controls = new Control[0]; protected int x, y, width, height; protected Robot robot = null; protected BufferedImage im = null; protected boolean mjpeg = false; public mjpegStream(MediaLocator locator) { super("http:" + locator.getRemainder()); System.out.println("http://" + locator.getRemainder()); try { super.connect(); im = super.readJPEG(); super.disconnect(); } catch(Exception e) { } if (im == null) { try { super.connect(); im = super.readMJPEG(); mjpeg = true; super.disconnect(); } catch(Exception e) { } } size = new Dimension(im.getWidth(), im.getHeight()); // im = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); // size = new Dimension(100, 100); maxDataLength = size.width * size.height * 3; rgbFormat = new RGBFormat( size, maxDataLength, Format.intArray, frameRate, 32, 0xFF0000, 0xFF00, 0xFF, 1, size.width, VideoFormat.FALSE, Format.NOT_SPECIFIED ); System.out.println(rgbFormat.getFrameRate()); // generate the data data = new int[maxDataLength]; thread = new Thread(this, "Htmjpeg Grabber"); } /*************************************************************************** * SourceStream ***************************************************************************/ public ContentDescriptor getContentDescriptor() { return cd; } public long getContentLength() { return LENGTH_UNKNOWN; } public boolean endOfStream() { return false; } /*************************************************************************** * PushBufferStream ***************************************************************************/ int seqNo = 0; public Format getFormat() { return rgbFormat; } public void read(Buffer buffer) throws IOException { synchronized (this) { super.connect(); Object outdata = buffer.getData(); if (outdata == null || !(outdata.getClass() == Format.intArray) || ((int[])outdata).length < maxDataLength) { outdata = new int[maxDataLength]; buffer.setData(outdata); } buffer.setFormat( rgbFormat ); buffer.setTimeStamp( (long) (seqNo * (1000 / frameRate) * 1000000) ); BufferedImage bi = mjpeg?super.readMJPEG():super.readJPEG(); bi.getRGB(0, 0, size.width, size.height, (int[])outdata, 0, size.width); buffer.setSequenceNumber( seqNo ); buffer.setLength(maxDataLength); buffer.setFlags(Buffer.FLAG_KEY_FRAME); buffer.setHeader( null ); seqNo++; if (!mjpeg) super.disconnect(); } } public void setTransferHandler(BufferTransferHandler transferHandler) { synchronized (this) { this.transferHandler = transferHandler; notifyAll(); } } void start(boolean started) { synchronized ( this ) { this.started = started; if (started && !thread.isAlive()) { thread = new Thread(this); thread.start(); } notifyAll(); } } /*************************************************************************** * Runnable ***************************************************************************/ public void run() { while (started) { synchronized (this) { while (transferHandler == null && started) { try { wait(1000); } catch (InterruptedException ie) { } } // while } if (started && transferHandler != null) { transferHandler.transferData(this); try { Thread.currentThread().sleep( 10 ); } catch (InterruptedException ise) { } } } // while (started) } // run // Controls public Object [] getControls() { return controls; } public Object getControl(String controlType) { try { Class cls = Class.forName(controlType); Object cs[] = getControls(); for (int i = 0; i < cs.length; i++) { if (cls.isInstance(cs[i])) return cs[i]; } return null; } catch (Exception e) { // no such controlType or such control return null; } } }