//3.3晚上修订版import java.io.IOException;import javax.media.Buffer;
import javax.media.CaptureDeviceManager;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.DataSink;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoProcessorException;
import javax.media.Player;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.protocol.SourceCloneable;
import javax.media.util.BufferToImage;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.RenderedImage;
import java.io.File;//public class WebCamSwing extends Object implements ActionListener
//public class WebCamSwing extends Container implements ActionListener
public class WebCamSwing extends Applet implements ActionListener {
String url = "vfw:Microsoft WDM Image Capture (Win32):0"; // 获取的摄像头信息
private CaptureDeviceInfo cdinfo = null; // 从获取的摄像头信息中提取的摄像头地址
private MediaLocator medialocator = null; // 原始的数据源
private DataSource datasource = null; // 由原始数据源转变成的,可以被克隆的数据源
private DataSource cloneabledatasource = null; // 由可以克隆的数据源cloneabledatasource克隆出来的cloneddatasource
private DataSource cloneddatasource = null; // 用来播放的player
public static Player player = null; // 处理录制的视频的Processor
private Processor processor = null; // 保存录制数据的数据池
private DataSink dataSink = null; private StateHelper sh = null; /** * ImagePanel类是将 */
private ImagePanel imgpanel = null; // buf用于截取实时图像的缓冲区
private Buffer buf = null; // 将buf转换为图像的“中间变量”
private BufferToImage btoi = null; // 拍下来的照片赋给img
private Image img = null; // 保存图片的宽度和高度
private int imgWidth = 320; private int imgHeight = 240; // 拍照按钮
private JButton capture = null; // 保存照片按钮
private JButton save = null; // 录像按钮
private JButton luxiang = null; // 停止录像按钮
private JButton tuichuluxiang = null; /**
* 此WebCamSwing函数完成的功能: 创建一个对话框。 将摄像头的物理地址转化为电脑能够识别的medialocator,
* 并且通过medialocator产生一个数据源datasource, 通过这个datasource数据源生成player用来播放视频。
* 然后将数据源进行处理,产生一个能够被克隆的cloneabledatasource,
* 再这个cloneabledatasource进行克隆,产生一个cloneddatasource数据源, 用于后面的processor录制视频
*/
public WebCamSwing() {
Panel editor = new Panel();
/** * */
editor.setPreferredSize(new Dimension());
editor.setLayout(null);
editor.setLayout(new GridLayout(1, 3));
imgpanel = new ImagePanel();
capture = new JButton("拍照");
capture.addActionListener(this);
save = new JButton("保存照片");
save.addActionListener(this);
luxiang = new JButton("开始录像");
luxiang.addActionListener(this);
tuichuluxiang = new JButton("停止录像");
tuichuluxiang.addActionListener(this);
cdinfo = CaptureDeviceManager.getDevice(url);
medialocator = cdinfo.getLocator();
try {
datasource = Manager.createDataSource(medialocator);
cloneabledatasource = Manager.createCloneableDataSource(datasource);
cloneddatasource = ((SourceCloneable) cloneabledatasource)
.createClone();
player = Manager.createRealizedPlayer(cloneabledatasource);
player.start();
Component comp;
if ((comp = player.getVisualComponent()) != null) {
add(comp);
}
Panel panel = new Panel(new GridLayout(4, 1));
panel.add(capture);
panel.add(save);
panel.add(luxiang);
panel.add(tuichuluxiang);
add(panel);
add(imgpanel); } catch (Exception b) {
b.printStackTrace();
} }
import javax.media.CaptureDeviceManager;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.DataSink;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoProcessorException;
import javax.media.Player;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.protocol.SourceCloneable;
import javax.media.util.BufferToImage;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.RenderedImage;
import java.io.File;//public class WebCamSwing extends Object implements ActionListener
//public class WebCamSwing extends Container implements ActionListener
public class WebCamSwing extends Applet implements ActionListener {
String url = "vfw:Microsoft WDM Image Capture (Win32):0"; // 获取的摄像头信息
private CaptureDeviceInfo cdinfo = null; // 从获取的摄像头信息中提取的摄像头地址
private MediaLocator medialocator = null; // 原始的数据源
private DataSource datasource = null; // 由原始数据源转变成的,可以被克隆的数据源
private DataSource cloneabledatasource = null; // 由可以克隆的数据源cloneabledatasource克隆出来的cloneddatasource
private DataSource cloneddatasource = null; // 用来播放的player
public static Player player = null; // 处理录制的视频的Processor
private Processor processor = null; // 保存录制数据的数据池
private DataSink dataSink = null; private StateHelper sh = null; /** * ImagePanel类是将 */
private ImagePanel imgpanel = null; // buf用于截取实时图像的缓冲区
private Buffer buf = null; // 将buf转换为图像的“中间变量”
private BufferToImage btoi = null; // 拍下来的照片赋给img
private Image img = null; // 保存图片的宽度和高度
private int imgWidth = 320; private int imgHeight = 240; // 拍照按钮
private JButton capture = null; // 保存照片按钮
private JButton save = null; // 录像按钮
private JButton luxiang = null; // 停止录像按钮
private JButton tuichuluxiang = null; /**
* 此WebCamSwing函数完成的功能: 创建一个对话框。 将摄像头的物理地址转化为电脑能够识别的medialocator,
* 并且通过medialocator产生一个数据源datasource, 通过这个datasource数据源生成player用来播放视频。
* 然后将数据源进行处理,产生一个能够被克隆的cloneabledatasource,
* 再这个cloneabledatasource进行克隆,产生一个cloneddatasource数据源, 用于后面的processor录制视频
*/
public WebCamSwing() {
Panel editor = new Panel();
/** * */
editor.setPreferredSize(new Dimension());
editor.setLayout(null);
editor.setLayout(new GridLayout(1, 3));
imgpanel = new ImagePanel();
capture = new JButton("拍照");
capture.addActionListener(this);
save = new JButton("保存照片");
save.addActionListener(this);
luxiang = new JButton("开始录像");
luxiang.addActionListener(this);
tuichuluxiang = new JButton("停止录像");
tuichuluxiang.addActionListener(this);
cdinfo = CaptureDeviceManager.getDevice(url);
medialocator = cdinfo.getLocator();
try {
datasource = Manager.createDataSource(medialocator);
cloneabledatasource = Manager.createCloneableDataSource(datasource);
cloneddatasource = ((SourceCloneable) cloneabledatasource)
.createClone();
player = Manager.createRealizedPlayer(cloneabledatasource);
player.start();
Component comp;
if ((comp = player.getVisualComponent()) != null) {
add(comp);
}
Panel panel = new Panel(new GridLayout(4, 1));
panel.add(capture);
panel.add(save);
panel.add(luxiang);
panel.add(tuichuluxiang);
add(panel);
add(imgpanel); } catch (Exception b) {
b.printStackTrace();
} }
/* 点击拍照 */
/*
* ActionEvent: 指示发生了组件定义的动作的语义事件。 当特定于组件的动作(比如
*
* 被按下)发生时, 由组件(比如 Button)生成此高级别事件。 事件被传递给每一个 ActionListener 对象, 这些对
*
* 象是使用组件的 addActionListener 方法注册的,用以接收这类事件。 注:要使用键盘在 Button 上触发
* ActionEvent,请使用空格键。
*/
public void actionPerformed(ActionEvent e) {
// ??捕获ActionEvent,将其转化为JComponent类,应该转化为是“单击按钮的意思”
JComponent c = (JComponent) e.getSource();
if (c == capture) {
// 取得对Player的控制
FrameGrabbingControl fgc = (FrameGrabbingControl) player
.getControl("javax.media.control.FrameGrabbingControl");
// 传输buf数据量大还是传输img数据量大??
buf = fgc.grabFrame();
btoi = new BufferToImage((VideoFormat) buf.getFormat());
img = btoi.createImage(buf);
imgpanel.setImage(img); } else if (c == save && img == null) {
JOptionPane.showMessageDialog(null, "请先拍照再保存"); }
// 保存图片
else if (c == save && img != null) {
Frame savephotoframe = new Frame("保存");
FileDialog savephotofiledialog = new FileDialog(savephotoframe,
"保存图像文件", FileDialog.SAVE); savephotofiledialog.setFile("*.GIF");
savephotofiledialog.setVisible(true);
String savepath = savephotofiledialog.getDirectory();
String savename = savephotofiledialog.getFile();
// ImageIO.write是将图片保存到上面已经写好的路径里,并且用上面的savename命名
try {
ImageIO.write((RenderedImage) img, "GIF", new File(savepath
+ savename)); } catch (IOException e1) {
// TODO 自动生成 catch 块
e1.printStackTrace();
}
img = null;
}
// 如果单击了“开始录像”按钮,但是processor不为空,那么就弹出提示表明正在录像
else if (c == luxiang && processor != null) {
JOptionPane.showMessageDialog(null, "正在录像!"); }
// 如果单击了“开始录像”按钮,且processor为空,那么就开始录像
else if (c == luxiang && processor == null) { Frame saveluxiangframe = new Frame("保存视频文件");
FileDialog fshipin = new FileDialog(saveluxiangframe, "保存视频文件",
FileDialog.SAVE);
fshipin.setFile("*.QUICKTIME");
fshipin.setVisible(true);
String luxiangsavepath = fshipin.getDirectory();
String luxiangsavename = fshipin.getFile();
// 如果输入了保存名字(没有点取消)的话,才可运行
if (luxiangsavename != null) {
// 后面的路径不认\\,只认/
luxiangsavepath.replace("\\", "/");
// 录像源代码
try {// player用cloneabledatasource数据源,processor用cloneddatasource的数据源
processor = Manager.createProcessor(cloneddatasource);
sh = new StateHelper(processor);
} catch (IOException ez5) {
ez5.printStackTrace();
System.exit(-1);
} catch (NoProcessorException ez6) {
ez6.printStackTrace();
System.exit(-1);
} // Configure the processor,让processor进入configured状态
if (!sh.configure(10000)) {
System.out.println("configure wrong!");
System.exit(-1);
} /*
* if ( processor instanceof Processor) processor.configure();
*/ // 设置视频输出格式
processor.setContentDescriptor(new FileTypeDescriptor(
FileTypeDescriptor.QUICKTIME)); // realize the processor,让processor进入realized状态
if (!sh.realize(10000)) {
System.out.println("realize wrong!");
System.exit(-1);
} // get the output of the processor,并且启动processor
DataSource outsource = processor.getDataOutput();
MediaLocator dest = new MediaLocator(new java.lang.String(
"file:///" + luxiangsavepath + luxiangsavename));
processor.start(); try {
dataSink = Manager.createDataSink(outsource, dest);
dataSink.open();
} catch (NoDataSinkException ez1) {
ez1.printStackTrace();
System.exit(-1);
} catch (IOException ez2) {
ez2.printStackTrace();
System.exit(-1);
} catch (SecurityException ez3) {
ez3.printStackTrace();
System.exit(-1);
} try {
dataSink.start();
} catch (IOException ez4) {
ez4.printStackTrace();
System.exit(-1);
} }
}
else if (c == tuichuluxiang && processor == null) {
JOptionPane.showMessageDialog(null, "请先单击录像才能停止!");
} else if (c == tuichuluxiang && processor != null) {
/*
* 如果要是能够连续录像,关键在于两点: 1 、重新设置cloneddatasource ,
* 我认为在cloneddatasource被调用后 , cloneddatasource被改变了 2、清空processor
*/
processor.close();
processor.deallocate();
dataSink.close();
cloneddatasource = ((SourceCloneable) cloneabledatasource)
.createClone();
processor = null;
}
} public class StateHelper implements javax.media.ControllerListener
{
Player xplayer = null; boolean configured = false; boolean realized = false;// boolean prefetched = false;// boolean eom = false;// End of media. boolean failed = false; boolean closed = false; public StateHelper(Player p)
{
xplayer = p;
p.addControllerListener(this);
} public boolean configure(int timeOutMillis)
{
//RealizeCompleteEvent发生了的话使ce事件与之比较,若相等,那么realized为true。
/*监听ConfigureCompleteEvent和ConfigureCompleteEvent事件的发生。
* 如ConfigureCompleteEvent事件发生,那么就会赋给configured为ture,
* 使得public boolean configure方法中的
* while (!configured && !failed){}这个循环退出。*/
long startTime = System.currentTimeMillis();
synchronized (this)
{
if (xplayer instanceof Processor)
((Processor) xplayer).configure();
else
return false;
while (!configured && !failed)
{
try
{
wait(timeOutMillis);
} catch (InterruptedException ie)
{
}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return configured;
} public boolean realize(int timeOutMillis)
{
long startTime = System.currentTimeMillis();
synchronized (this)
{
xplayer.realize();
while (!realized && !failed)
{
try
{
wait(timeOutMillis);
} catch (InterruptedException ie)
{
}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return realized;
} public synchronized void controllerUpdate(ControllerEvent ce)
{
if (ce instanceof RealizeCompleteEvent)
{
realized = true;
} else if (ce instanceof ConfigureCompleteEvent)
{
configured = true;
} else
{
return;
}
notifyAll();
}
} class ImagePanel extends Panel {
private Image ImagePanelimg = null; public ImagePanel() {
setLayout(null);
setSize(imgWidth, imgHeight);
} public void setImage(Image img) {
this.ImagePanelimg = img;
this.setVisible(true);
repaint();
} public void update(Graphics graphics) {
if (ImagePanelimg != null) {
graphics.drawImage(ImagePanelimg, 0, 0, this);
}
}
} public static void main(String[] args) {
Frame frame = new Frame("拍照程序");
WebCamSwing cf = new WebCamSwing();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0);
} });
frame.add("Center", cf);
frame.pack();
frame.setVisible(true);
}}
这是我的原代码,能够完成将摄像头数据捕获并保存为QUICKTIME格式的文件,但是将源代码中的
fshipin.setFile("*.quicktime");中的QuickTime改为mpg
和
processor.setContentDescriptor(new FileTypeDescriptor(
FileTypeDescriptor.QUICKTIME));
这一句中的QUICKTIME改为MPEG
就会出现如下错误:
javax.media.NoDataSinkException: Cannot find a DataSink for: com.sun.media.multiplexer.RawBufferMux$RawBufferDataSource@1f5d386
at javax.media.Manager.createDataSink(Manager.java:1894)
at WebCamSwing.actionPerformed(WebCamSwing.java:245)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6038)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5803)
at java.awt.Container.processEvent(Container.java:2058)
at java.awt.Component.dispatchEventImpl(Component.java:4410)
at java.awt.Container.dispatchEventImpl(Container.java:2116)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
at java.awt.Container.dispatchEventImpl(Container.java:2102)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
else if (c == tuichuluxiang && processor == null) {
JOptionPane.showMessageDialog(null, "请先单击录像才能停止!");
} else if (c == tuichuluxiang && processor != null) {
/*
* 如果要是能够连续录像,关键在于两点: 1 、重新设置cloneddatasource ,
* 我认为在cloneddatasource被调用后 , cloneddatasource被改变了 2、清空processor
*/
processor.close();
processor.deallocate();
dataSink.close();
cloneddatasource = ((SourceCloneable) cloneabledatasource)
.createClone();
processor = null;
}
} public class StateHelper implements javax.media.ControllerListener
{
Player xplayer = null; boolean configured = false; boolean realized = false;// boolean prefetched = false;// boolean eom = false;// End of media. boolean failed = false; boolean closed = false; public StateHelper(Player p)
{
xplayer = p;
p.addControllerListener(this);
} public boolean configure(int timeOutMillis)
{
//RealizeCompleteEvent发生了的话使ce事件与之比较,若相等,那么realized为true。
/*监听ConfigureCompleteEvent和ConfigureCompleteEvent事件的发生。
* 如ConfigureCompleteEvent事件发生,那么就会赋给configured为ture,
* 使得public boolean configure方法中的
* while (!configured && !failed){}这个循环退出。*/
long startTime = System.currentTimeMillis();
synchronized (this)
{
if (xplayer instanceof Processor)
((Processor) xplayer).configure();
else
return false;
while (!configured && !failed)
{
try
{
wait(timeOutMillis);
} catch (InterruptedException ie)
{
}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return configured;
} public boolean realize(int timeOutMillis)
{
long startTime = System.currentTimeMillis();
synchronized (this)
{
xplayer.realize();
while (!realized && !failed)
{
try
{
wait(timeOutMillis);
} catch (InterruptedException ie)
{
}
if (System.currentTimeMillis() - startTime > timeOutMillis)
break;
}
}
return realized;
} public synchronized void controllerUpdate(ControllerEvent ce)
{
if (ce instanceof RealizeCompleteEvent)
{
realized = true;
} else if (ce instanceof ConfigureCompleteEvent)
{
configured = true;
} else
{
return;
}
notifyAll();
}
} class ImagePanel extends Panel {
private Image ImagePanelimg = null; public ImagePanel() {
setLayout(null);
setSize(imgWidth, imgHeight);
} public void setImage(Image img) {
this.ImagePanelimg = img;
this.setVisible(true);
repaint();
} public void update(Graphics graphics) {
if (ImagePanelimg != null) {
graphics.drawImage(ImagePanelimg, 0, 0, this);
}
}
} public static void main(String[] args) {
Frame frame = new Frame("拍照程序");
WebCamSwing cf = new WebCamSwing();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0);
} });
frame.add("Center", cf);
frame.pack();
frame.setVisible(true);
}}
这是我的原代码,能够完成将摄像头数据捕获并保存为QUICKTIME格式的文件,但是将源代码中的
fshipin.setFile("*.quicktime");中的QuickTime改为mpg
和
processor.setContentDescriptor(new FileTypeDescriptor(
FileTypeDescriptor.QUICKTIME));
这一句中的QUICKTIME改为MPEG
就会出现如下错误:
javax.media.NoDataSinkException: Cannot find a DataSink for: com.sun.media.multiplexer.RawBufferMux$RawBufferDataSource@1f5d386
at javax.media.Manager.createDataSink(Manager.java:1894)
at WebCamSwing.actionPerformed(WebCamSwing.java:245)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6038)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5803)
at java.awt.Container.processEvent(Container.java:2058)
at java.awt.Component.dispatchEventImpl(Component.java:4410)
at java.awt.Container.dispatchEventImpl(Container.java:2116)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
at java.awt.Container.dispatchEventImpl(Container.java:2102)
at java.awt.Component.dispatchEvent(Component.java:4240)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
我用你写的程序,可以保存照片,但是不能保存视频,报一下错误: No permission to write files from applets ,这个如何解决??真的很期待你的回答,非常感谢!!!
我的QQ419984686
Bad header in the media: strh: header length should be atleast 56 but is 52Error: Unable to realize com.sun.media.PlaybackEngine@1551b0