📄 framegrabber.java
字号:
/**
* JMF/Webcam Frame Grabber Demo
*
* @author S.Ritter 24.01.2002
* @version 1.0
*
* ALL EXAMPLES OF CODE AND/OR COMMAND-LINE INSTRUCTIONS ARE BEING
* PROVIDED BY SUN AS A COURTESY, "AS IS," AND SUN DISCLAIMS ANY AND
* ALL WARRANTIES PERTAINING THERETO, INCLUDING ANY WARRANTIES OF
* MERCHANTABILTY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* SUN IS NOT LICENSING THIS EXAMPLE FOR ANY USE OTHER THAN FOR THE
* EDUCATIONAL PURPOSE OF SHOWING THE FUNCTIONALITY CONTAINED
* THEREIN, BY WAY OF EXAMPLE.
**/
package cie.mobile.video;
import java.io.*;
import java.awt.*;
import java.awt.image.*;
import java.util.Properties;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.media.util.*;
import javax.media.format.RGBFormat;
/**
* Frame grabber class
*/
public class FrameGrabber extends Thread implements ControllerListener {
/*
* Default device name and format parameters to use
* if no properties file is provided
*/
//private final static String DEFAULT_DEV_NAME =
// "v4l:Logitech QuickCam Pro 4000:0";
//private final static String DEFAULT_DEV_NAME =
//"vfw:Microsoft WDM Image Capture (Win32):0";
//private Properties videoProperties;
/*
* These objects are used for controlling access via wait and notify to
* ensure that the processor has been realised and the second thread has
* completed it's startup
*/
private Object stateLock = new Object();
private Object runLock = new Object();
private Processor deviceProc = null;
private PushBufferStream camStream;
private PushBufferDataSource source = null;
private BufferToImage converter;
private Image currentImage;
private boolean threadRunning = false;
private boolean bPause = false;
/**
* Constructor
*
* @param videoPropFile
* The name of the video properties file
* @throws FrameGrabberException
* If we can't start up the camera
*/
public FrameGrabber(String driver, String size_x, String size_y)
throws FrameGrabberException
{
setup(driver, size_x, size_y);
}
/**
* Setup method; Configures webcam and JMF ready to get images
*
* @param videoPropFile
* The name of the video properties file
* @throws FrameGrabberException
* If we can't start up the camera
*/
private void setup(String driver, String size_x, String size_y)
throws FrameGrabberException
{
Dimension viewSize = null;
int viewDepth = 0;
String cameraDevice = driver;
/*
* Get the parameters for the video capture device
* from the properties file.
* If not defined use default values
*/
try {
String pValue = size_x;
int xRes = Integer.parseInt(pValue);
pValue = size_y;
int yRes = Integer.parseInt(pValue);
viewSize = new Dimension(xRes, yRes);
} catch (NumberFormatException nfe) {
System.out.println("Bad numeric value in parameter");
System.exit(1);
}
/*
* Try to get the CaptureDevice that matches
* the name supplied by the user
*/
CaptureDeviceInfo device = CaptureDeviceManager.getDevice(cameraDevice);
if (device == null)
throw new FrameGrabberException("No device found [" + cameraDevice
+ "]");
RGBFormat userFormat = null;
Format[] cfmt = device.getFormats();
/* Find the format that the user has requested (if available) */
for (int i = 0; i < cfmt.length; i++) {
if (cfmt[i] instanceof RGBFormat) {
userFormat = (RGBFormat) cfmt[i];
Dimension d = userFormat.getSize();
if (viewSize.equals(d))
break;
userFormat = null;
}
}
/*
* Throw an exception if we can't find a format that
* matches the user's criteria
*/
if (userFormat == null)
throw new FrameGrabberException("Requested format not supported");
/* To use this device we need a MediaLocator */
MediaLocator loc = device.getLocator();
if (loc == null)
throw new FrameGrabberException(
"Unable to get MediaLocator for device");
DataSource formattedSource = null;
/*
* Now create a dataSource for this device and
* set the format to the one chosen by the user.
*/
try {
formattedSource = Manager.createDataSource(loc);
} catch (IOException ioe) {
throw new FrameGrabberException("IO Error creating dataSource");
} catch (NoDataSourceException ndse) {
throw new FrameGrabberException("Unable to create dataSource");
}
/*
* Setting the format is rather complicated.
* Firstly we need to get the format controls from
* the dataSource we just created. In order to do
* this we need a reference to an object
* implementing the CaptureDevice
* interface (which DataSource objects can).
*/
if (!(formattedSource instanceof CaptureDevice))
throw new FrameGrabberException("DataSource not a CaptureDevice");
FormatControl[] fmtControls = ((CaptureDevice) formattedSource)
.getFormatControls();
if (fmtControls == null || fmtControls.length == 0)
throw new FrameGrabberException("No FormatControl available");
Format setFormat = null;
/*
* Now we need to loop through the available
* FormatControls and try to set the format to the
* one we want. According to the documentation even
* though this may appear to work, it may fail later on.
* Since we know that the format is supported
* we hope that this won't happen
*/
for (int i = 0; i < fmtControls.length; i++) {
if (fmtControls[i] == null)
continue;
if ((setFormat = fmtControls[i].setFormat(userFormat)) != null)
break;
}
/* Throw an exception if we couldn't set the format */
if (setFormat == null)
throw new FrameGrabberException("Failed to set camera format");
/* Connect to the DataSource */
try {
formattedSource.connect();
} catch (IOException ioe) {
throw new FrameGrabberException("Unable to connect to DataSource");
}
/*
* Since we don't want to display the output to
* the user at this stage we use a processor rather
* than a player to get frame access
*/
try {
deviceProc = Manager.createProcessor(formattedSource);
} catch (IOException ioe) {
throw new FrameGrabberException(
"Unable to get Processor for device: " + ioe.getMessage());
} catch (NoProcessorException npe) {
throw new FrameGrabberException(
"Unable to get Processor for device: " + npe.getMessage());
}
/*
* In order to use the controller we have to put it
* in the realized state. We do this by calling the
* realize method, but this will return immediately
* so we must register a listener (this class) to be
* notified when the controller is ready.
*/
deviceProc.addControllerListener(this);
deviceProc.realize();
/*
* Wait for the device to send an event telling us
* that it has reached the realized state
*/
while (deviceProc.getState() != Controller.Realized) {
synchronized (stateLock) {
try {
stateLock.wait();
} catch (InterruptedException ie) {
throw new FrameGrabberException(
"Failed to get to realized state");
}
}
}
deviceProc.start();
/*
* Get access to the PushBufferDataSource which will
* provide us with a means to get at the frame grabber
*/
try {
source = (PushBufferDataSource) deviceProc.getDataOutput();
} catch (NotRealizedError nre) {
/* Should never happen */
throw new FrameGrabberException("Processor not realized");
}
/*
* Now we can retrieve the PushBufferStreams
* that will enable us to
* access the data from the camera
*/
PushBufferStream[] streams = source.getStreams();
camStream = null;
for (int i = 0; i < streams.length; i++) {
/* Use the first Stream that is RGBFormat (there should be only one */
if (streams[i].getFormat() instanceof RGBFormat) {
camStream = streams[i];
RGBFormat yuvf = (RGBFormat) streams[i].getFormat();
converter = new BufferToImage(yuvf);
System.out.println("converter is initialized here!");
break;
}
}
System.out.println("Capture device ready");
}
/**
* Get an image from the camera as an AWT Image object
*
* @returns The current image from the camera
*/
public Image getImage() {
/*
* Since we are using a second thread to grab the
* images from the webcam we need to ensure that
* an image has been aquired. We do this
* by using a flag which will be set to true in
* the run() method. If this is false we wait until
* the run method notifies us that there is
* an image to collect
*/
while (threadRunning == false) {
synchronized (runLock) {
try {
runLock.wait();
} catch (InterruptedException ie) {
// Ignore
}
}
}
return accessInternalImage(null);
}
/**
* Get an image from the camera as a BufferedImage
*
* @returns The current image from the camera
*/
public BufferedImage getBufferedImage() {
return (BufferedImage) getImage();
}
/**
* Run method for Thread class
*/
public void run() {
System.out.println("Capture thread starting...");
Buffer b = new Buffer();
/*
* Simply loop forever grabbing images from the
* web cam and storing them so that the user can
* retrieve them when required.
*/
while (!bPause){
try {
camStream.read(b);
} catch (Exception e) {
// Ignore. Nothing we can really do about this
}
Image i = converter.createImage(b);
accessInternalImage(i);
/*
* If this is the first image we've collected
* we need to advertise to the main thread that
* there is an image ready and then notify
* the main thread in case it is waiting on the image
*/
if (!threadRunning) {
threadRunning = true;
synchronized (runLock) {
runLock.notifyAll();
}
}
}
deviceProc.stop();
deviceProc.close();
}
/**
* Method called when a controller event is received (implements
* ControllerListener interface)
*
* @param ce
* The controller event
*/
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof RealizeCompleteEvent) {
synchronized (stateLock) {
stateLock.notifyAll();
}
}
}
/**
* Method that controls access to the global image variable.
* This ensures that there is no confusion over one thread
* reading an image whilst another is writing to it
*
* @param image
* The image to store (null indicates retrieval of the image)
* @return The image (if the parameter was null)
*/
private synchronized Image accessInternalImage(Image image) {
if (image == null) {
return currentImage;
}
currentImage = image;
return null;
}
public void stopFetch()
{
bPause = true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -