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;
}
}
}