JWebCam.java
package ac.essex.ooechs.imaging.commons.apps.webcam;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import javax.media.*;
import javax.media.format.*;
import javax.media.util.*;
import javax.media.control.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import com.sun.image.codec.jpeg.*;
public class JWebCam extends JFrame implements WindowListener, ComponentListener {
protected final static int MIN_WIDTH = 100; // 320;
protected final static int MIN_HEIGHT = 100; // 240;
protected static int shotCounter = 1;
protected JLabel statusBar = null;
protected JPanel visualContainer = null;
protected Component visualComponent = null;
protected JToolBar toolbar = null;
protected MyToolBarAction formatButton = null;
protected MyToolBarAction captureButton = null;
protected Player player = null;
protected CaptureDeviceInfo webCamDeviceInfo = null;
protected MediaLocator ml = null;
protected Dimension imageSize = null;
protected FormatControl formatControl = null;
protected VideoFormat currentFormat = null;
protected Format[] videoFormats = null;
protected MyVideoFormat[] myFormatList = null;
protected MyCaptureDeviceInfo[] myCaptureDevices = null;
protected boolean initialised = false;
/* --------------------------------------------------------------
* Constructor
* -------------------------------------------------------------- */
public JWebCam(String frameTitle) {
super(frameTitle);
/* try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
System.out.println("Unable to load native look and feel");
}*/
setSize(320, 260); // default size...
addWindowListener(this);
addComponentListener(this);
getContentPane().setLayout(new BorderLayout());
visualContainer = new JPanel();
visualContainer.setLayout(new BorderLayout());
getContentPane().add(visualContainer, BorderLayout.CENTER);
statusBar = new JLabel("") {
// Nasty bug workaround
// The minimum JLabel size was determined by the text in the status bar
// So the layoutmanager wouldn't shrink the window for the video image
public Dimension getPreferredSize() {
// get the JLabel to "allow" a minimum of 10 pixels width
// not to work out the minimum size from the text length
return (new Dimension(10, super.getPreferredSize().height));
}
};
statusBar.setBorder(new EtchedBorder());
getContentPane().add(statusBar, BorderLayout.SOUTH);
}
/* --------------------------------------------------------------
* Initialise
*
* @returns true if web cam is detected
* -------------------------------------------------------------- */
public boolean initialise()
throws Exception {
MyCaptureDeviceInfo[] cams = autoDetect();
if (cams.length > 0) {
if (cams.length == 1) {
System.out.println("Note : 1 web cam detected");
return (initialise(cams[0].capDevInfo));
} else {
System.out.println("Note : " + cams.length + " web cams detected");
Object selected = JOptionPane.showInputDialog(this,
"Select Video format",
"Capture format selection",
JOptionPane.INFORMATION_MESSAGE,
null, // Icon icon,
cams, // videoFormats,
cams[0]);
if (selected != null) {
return (initialise(((MyCaptureDeviceInfo) selected).capDevInfo));
} else {
return (initialise(null));
}
}
} else {
return (initialise(null));
}
}
/* -------------------------------------------------------------------
* Initialise
*
* @params _deviceInfo, specific web cam device if not autodetected
* @returns true if web cam is detected
* ------------------------------------------------------------------- */
public boolean initialise(CaptureDeviceInfo _deviceInfo) throws Exception {
statusBar.setText("Initialising...");
webCamDeviceInfo = _deviceInfo;
if (webCamDeviceInfo != null) {
statusBar.setText("Connecting to : " + webCamDeviceInfo.getName());
try {
setUpToolBar();
getContentPane().add(toolbar, BorderLayout.NORTH);
ml = webCamDeviceInfo.getLocator();
if (ml != null) {
player = Manager.createRealizedPlayer(ml);
if (player != null) {
player.start();
formatControl = (FormatControl) player.getControl("javax.media.control.FormatControl");
videoFormats = webCamDeviceInfo.getFormats();
myFormatList = new MyVideoFormat[videoFormats.length];
for (int i = 0; i < videoFormats.length; i++) {
myFormatList[i] = new MyVideoFormat((VideoFormat) videoFormats[i]);
}
Format currFormat = formatControl.getFormat();
visualComponent = player.getVisualComponent();
if (visualComponent != null) {
visualContainer.add(visualComponent, BorderLayout.CENTER);
if (currFormat instanceof VideoFormat) {
currentFormat = (VideoFormat) currFormat;
imageSize = currentFormat.getSize();
visualContainer.setPreferredSize(imageSize);
setSize(imageSize.width, imageSize.height + statusBar.getHeight() + toolbar.getHeight());
} else {
System.err.println("Error : Cannot get current video format");
}
invalidate();
pack();
return (true);
} else {
System.err.println("Error : Could not get visual component");
return (false);
}
} else {
System.err.println("Error : Cannot create player");
statusBar.setText("Cannot create player");
return (false);
}
} else {
System.err.println("Error : No MediaLocator for " + webCamDeviceInfo.getName());
statusBar.setText("No Media Locator for : " + webCamDeviceInfo.getName());
return (false);
}
}
catch (IOException ioEx) {
System.err.println("Error connecting to [" + webCamDeviceInfo.getName() + "] : " + ioEx.getMessage());
statusBar.setText("Connecting to : " + webCamDeviceInfo.getName());
return (false);
}
catch (NoPlayerException npex) {
statusBar.setText("Cannot create player");
return (false);
}
catch (CannotRealizeException nre) {
statusBar.setText("Cannot realize player");
return (false);
}
} else {
return (false);
}
}
/* -------------------------------------------------------------------
* Dynamically create menu items
*
* @returns the device info object if found, null otherwise
* ------------------------------------------------------------------- */
public void setFormat(VideoFormat selectedFormat) {
if (formatControl != null) {
player.stop();
currentFormat = selectedFormat;
if (visualComponent != null) {
visualContainer.remove(visualComponent);
}
imageSize = currentFormat.getSize();
visualContainer.setPreferredSize(imageSize);
statusBar.setText("Format : " + currentFormat);
System.out.println("Format : " + currentFormat);
formatControl.setFormat(currentFormat);
player.start();
visualComponent = player.getVisualComponent();
if (visualComponent != null) {
visualContainer.add(visualComponent, BorderLayout.CENTER);
}
invalidate(); // let the layout manager work out the sizes
pack();
} else {
System.out.println("Visual component not an instance of FormatControl");
statusBar.setText("Visual component cannot change format");
}
}
public VideoFormat getFormat() {
return (currentFormat);
}
protected void setUpToolBar() {
toolbar = new JToolBar();
// Note : due to cosmetic glitches when undocking and docking the toolbar,
// I've set this to false.
toolbar.setFloatable(false);
// Note : If you supply the 16 x 16 bitmaps then you can replace
// the commented line in the MyToolBarAction constructor
formatButton = new MyToolBarAction("Resolution", "BtnFormat.jpg");
captureButton = new MyToolBarAction("Capture", "BtnCapture.jpg");
toolbar.add(formatButton);
toolbar.add(captureButton);
getContentPane().add(toolbar, BorderLayout.NORTH);
}
protected void toolbarHandler(MyToolBarAction actionBtn) {
if (actionBtn == formatButton) {
Object selected = JOptionPane.showInputDialog(this,
"Select Video format",
"Capture format selection",
JOptionPane.INFORMATION_MESSAGE,
null, // Icon icon,
myFormatList, // videoFormats,
currentFormat);
if (selected != null) {
setFormat(((MyVideoFormat) selected).format);
}
} else if (actionBtn == captureButton) {
Image photo = grabFrameImage();
if (photo != null) {
MySnapshot snapshot = new MySnapshot(photo, new Dimension(imageSize));
} else {
System.err.println("Error : Could not grab frame");
}
}
}
/* -------------------------------------------------------------------
* autoDetects the first web camera in the system
* searches for video for windows ( vfw ) capture devices
*
* @returns the device info object if found, null otherwise
* ------------------------------------------------------------------- */
public MyCaptureDeviceInfo[] autoDetect() {
Vector list = CaptureDeviceManager.getDeviceList(null);
CaptureDeviceInfo devInfo = null;
String name;
Vector capDevices = new Vector();
if (list != null) {
for (int i = 0; i < list.size(); i++) {
devInfo = (CaptureDeviceInfo) list.elementAt(i);
name = devInfo.getName();
if (name.startsWith("vf")) {
System.out.println("DeviceManager List : " + name);
capDevices.addElement(new MyCaptureDeviceInfo(devInfo));
}
System.out.println(name);
}
}
MyCaptureDeviceInfo[] detected = new MyCaptureDeviceInfo[capDevices.size()];
for (int i = 0; i < capDevices.size(); i++) {
detected[i] = (MyCaptureDeviceInfo) capDevices.elementAt(i);
}
return (detected);
}
/* -------------------------------------------------------------------
* deviceInfo
*
* @note outputs text information
* ------------------------------------------------------------------- */
public void deviceInfo() {
if (webCamDeviceInfo != null) {
Format[] formats = webCamDeviceInfo.getFormats();
if ((formats != null) && (formats.length > 0)) {
}
for (int i = 0; i < formats.length; i++) {
Format aFormat = formats[i];
if (aFormat instanceof VideoFormat) {
Dimension dim = ((VideoFormat) aFormat).getSize();
// System.out.println ("Video Format " + i + " : " + formats[i].getEncoding() + ", " + dim.width + " x " + dim.height );
}
}
} else {
System.out.println("Error : No web cam detected");
}
}
/* -------------------------------------------------------------------
* grabs a frame's buffer from the web cam / device
*
* @returns A frames buffer
* ------------------------------------------------------------------- */
public Buffer grabFrameBuffer() {
if (player != null) {
FrameGrabbingControl fgc = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
if (fgc != null) {
return (fgc.grabFrame());
} else {
System.err.println("Error : FrameGrabbingControl is null");
return (null);
}
} else {
System.err.println("Error : Player is null");
return (null);
}
}
/* -------------------------------------------------------------------
* grabs a frame's buffer, as an image, from the web cam / device
*
* @returns A frames buffer as an image
* ------------------------------------------------------------------- */
public Image grabFrameImage() {
Buffer buffer = grabFrameBuffer();
if (buffer != null) {
// Convert it to an image
BufferToImage btoi = new BufferToImage((VideoFormat) buffer.getFormat());
if (btoi != null) {
Image image = btoi.createImage(buffer);
if (image != null) {
return (image);
} else {
System.err.println("Error : BufferToImage cannot convert buffer");
return (null);
}
} else {
System.err.println("Error : cannot create BufferToImage instance");
return (null);
}
} else {
System.out.println("Error : Buffer grabbed is null");
return (null);
}
}
/* -------------------------------------------------------------------
* Closes and cleans up the player
*
* ------------------------------------------------------------------- */
public void playerClose() {
if (player != null) {
player.close();
player.deallocate();
player = null;
}
}
public void windowClosing(WindowEvent e) {
playerClose();
System.exit(1);
}
public void componentResized(ComponentEvent e) {
Dimension dim = getSize();
boolean mustResize = false;
if (dim.width < MIN_WIDTH) {
dim.width = MIN_WIDTH;
mustResize = true;
}
if (dim.height < MIN_HEIGHT) {
dim.height = MIN_HEIGHT;
mustResize = true;
}
if (mustResize)
setSize(dim);
}
public void windowActivated(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
public void componentHidden(ComponentEvent e) {
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
protected void finalize() throws Throwable {
playerClose();
super.finalize();
}
class MyToolBarAction extends AbstractAction {
public MyToolBarAction(String name, String imagefile) {
// Note : Use version this if you supply your own toolbar icons
// super ( name, new ImageIcon ( imagefile ) );
super(name);
}
public void actionPerformed(ActionEvent event) {
toolbarHandler(this);
}
}
class MyCaptureDeviceInfo {
public CaptureDeviceInfo capDevInfo;
public MyCaptureDeviceInfo(CaptureDeviceInfo devInfo) {
capDevInfo = devInfo;
}
public String toString() {
return (capDevInfo.getName());
}
}
class MySnapshot extends JFrame implements ImageObserver {
protected Image photo = null;
protected int shotNumber;
public MySnapshot(Image grabbedFrame, Dimension imageSize) {
super();
shotNumber = shotCounter++;
setTitle("Photo" + shotNumber);
photo = grabbedFrame;
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int imageHeight = photo.getWidth(this);
int imageWidth = photo.getHeight(this);
setSize(imageSize.width, imageSize.height);
final FileDialog saveDialog = new FileDialog(this, "Save JPEG", FileDialog.SAVE);
final JFrame thisCopy = this;
saveDialog.setFile("Photo" + shotNumber);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
saveDialog.show();
String filename = saveDialog.getFile();
if (filename != null) {
if (saveJPEG(filename)) {
JOptionPane.showMessageDialog(thisCopy, "Saved " + filename);
setVisible(false);
dispose();
} else {
JOptionPane.showMessageDialog(thisCopy, "Error saving " + filename);
}
} else {
setVisible(false);
dispose();
}
}
}
);
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(photo, 0, 0, getWidth(), getHeight(), Color.black, this);
}
/* -------------------------------------------------------------------
* Saves an image as a JPEG
*
* @params the image to save
* @params the filename to save the image as
* ------------------------------------------------------------------- */
public boolean saveJPEG(String filename) {
boolean saved = false;
BufferedImage bi = new BufferedImage(photo.getWidth(null),
photo.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bi.createGraphics();
g2.drawImage(photo, null, null);
FileOutputStream out = null;
try {
out = new FileOutputStream(filename);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
param.setQuality(1.0f, false); // 100% high quality setting, no compression
encoder.setJPEGEncodeParam(param);
encoder.encode(bi);
out.close();
saved = true;
}
catch (Exception ex) {
System.out.println("Error saving JPEG : " + ex.getMessage());
}
return (saved);
}
} // of MySnapshot
public static void main(String[] args) {
try {
JWebCam myWebCam = new JWebCam("Web Cam Capture");
myWebCam.setVisible(true);
if (!myWebCam.initialise()) {
System.out.println("Web Cam not detected / initialised");
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}