1. 1、捕获媒体数据的步骤:
l 查询CaptureDeviceManager,来定位你需要使用的媒体采集设备。
l 得到此设备的CaptureDeviceInfo实例。
l 从此CaptureDeviceInfo实例获得一个MediaLocator,并通过它来创建一个DataSource。
l 用此DataSource创建一个Player或Processor。
l 启动此Player或Processor开始捕获媒体数据。
2.CaptureDeviceManager、CaptureDeviceInfo、MediaLocator
在JMF中,CaptureDeviceManager也是一个manager类,它提供给了一个列表,这个列表显示当前系统可以被使用的设备名称。同时CaptureDeviceManager可以通过查询的方法对设备进行定位并返回设备的配置信息对象CaptureDeviceInfo,它也可以通过注册的方法向列表加入一个新的设备信息,以便为JMF使用。
设备可通过CaptureDeviceManager的getDevice()方法直接获得设备控制权,设备的控制权一旦得到,就可以以此设备作为一个MediaLocator,可以通过CaptureDeviceInfo的getLocator()方法得到。
3. JMF识别的音频采集设备
4.一个实例实现音频捕获
实例有两个文件组成。CaptureAudio.java实现
①查询、获得音频采集设备。
②捕获音频。
③将音频保存到本地文件foo.wav。
StateHelper实现处理器(processor)的状态控制管理。以下为流程图:
5.音频捕获代码实例:
CaptureAudio.java
import java.io.IOException; import java.util.Vector;
import javax.media.CaptureDeviceInfo; import javax.media.CaptureDeviceManager; import javax.media.DataSink; import javax.media.Manager; import javax.media.MediaLocator; import javax.media.NoDataSinkException; import javax.media.NoProcessorException; import javax.media.Processor; import javax.media.control.StreamWriterControl; import javax.media.format.AudioFormat; import javax.media.protocol.DataSource; import javax.media.protocol.FileTypeDescriptor;
public class CaptureAudio { /** * Writing captured audio to a file with a DataSink. */ public static void main(String[] args) { CaptureDeviceInfo di = null; Processor p = null; StateHelper sh = null; //查询CaptureDeviceManager,来定位你需要使用的媒体采集设备。 Vector deviceList = CaptureDeviceManager.getDeviceList(new AudioFormat(AudioFormat.LINEAR, 44100, 16, 2)); if (deviceList.size() > 0){ //得到此设备的CaptureDeviceInfo实例。 di = (CaptureDeviceInfo)deviceList.firstElement(); } else // 找不到满足(linear, 44100Hz, 16 bit,stereo audio.)音频设备,退出。 System.exit(-1); try { //获得MediaLocator,并由此创建一个Processor。 p = Manager.createProcessor(di.getLocator()); sh = new StateHelper(p); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } catch (NoProcessorException e) { e.printStackTrace(); System.exit(-1); } // Configure the processor if (!sh.configure(10000)){ System.out.println("configure wrong!"); System.exit(-1); } //定义待存储该媒体的内容类型(content type)。 p.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.WAVE)); // realize the processor. if (!sh.realize(10000)){ System.out.println("realize wrong!"); System.exit(-1); } // get the output of the processor DataSource source = p.getDataOutput(); //定义存储该媒体的文件。 MediaLocator dest = new MediaLocator(new java.lang.String( "file:///D:/Dvp/workspace/JavaSoundMedia/foo.wav")); //创建一个数据池 DataSink filewriter = null; try { filewriter = Manager.createDataSink(source, dest); filewriter.open(); } catch (NoDataSinkException e) { e.printStackTrace(); System.exit(-1); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } catch (SecurityException e) { e.printStackTrace(); System.exit(-1); } // if the Processor implements StreamWriterControl, we can // call setStreamSizeLimit // to set a limit on the size of the file that is written. StreamWriterControl swc = (StreamWriterControl) p.getControl("javax.media.control.StreamWriterControl"); //set limit to 5MB if (swc != null) swc.setStreamSizeLimit(5000000); // now start the filewriter and processor try { filewriter.start(); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } // Capture for 5 seconds sh.playToEndOfMedia(5000); sh.close(); // Wait for an EndOfStream from the DataSink and close it... filewriter.close(); } } |
StateHelper.java
import javax.media.*;
public class StateHelper implements javax.media.ControllerListener { Player player = 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) { player = p; p.addControllerListener(this); } /** * To judge whether the processor is configured. * Configure the processor in the given time which is limited * by the timeOutMillis.Once a Processor is Configured, you * can set its output format and TrackControl options. */ public boolean configure(int timeOutMillis) { long startTime = System.currentTimeMillis(); synchronized (this) { if (player instanceof Processor) ((Processor)player).configure(); else return false; while (!configured && !failed) { try { wait(timeOutMillis); } catch (InterruptedException ie) { } if (System.currentTimeMillis() - startTime > timeOutMillis) break; } } return configured; } /** * To judge whether the playerr is realized. */ public boolean realize(int timeOutMillis) { long startTime = System.currentTimeMillis(); synchronized (this) { player.realize(); while (!realized && !failed) { try { wait(timeOutMillis); } catch (InterruptedException ie) { } if (System.currentTimeMillis() - startTime > timeOutMillis) break; } } return realized; } /** * To judge whether the player is prefetched. */ public boolean prefetch(int timeOutMillis) { long startTime = System.currentTimeMillis(); synchronized (this) { player.prefetch(); while (!prefetched && !failed) { try { wait(timeOutMillis); } catch (InterruptedException ie) { } if (System.currentTimeMillis() - startTime > timeOutMillis) break; } } return prefetched && !failed; } /** * To judge whether the player has finished. */ public boolean playToEndOfMedia(int timeOutMillis) { long startTime = System.currentTimeMillis(); eom = false; synchronized (this) { player.start(); while (!eom && !failed) { try { wait(timeOutMillis); } catch (InterruptedException ie) { } if (System.currentTimeMillis() - startTime > timeOutMillis) break; } } return eom && !failed; } public void close() { synchronized (this) { player.close(); while (!closed) { try { wait(100); } catch (InterruptedException ie) { } } } player.removeControllerListener(this); } public synchronized void controllerUpdate(ControllerEvent ce) { if (ce instanceof RealizeCompleteEvent) { realized = true; } else if (ce instanceof ConfigureCompleteEvent) { configured = true; } else if (ce instanceof PrefetchCompleteEvent) { prefetched = true; } else if (ce instanceof EndOfMediaEvent) { eom = true; } else if (ce instanceof ControllerErrorEvent) { failed = true; } else if (ce instanceof ControllerClosedEvent) { closed = true; } else { return; } notifyAll(); } } |
6.关于视频捕获
6.1VFW(Video for Windows)
在阐述如何识别视频采集设备之前,我们先引入VFW概念:
VFW 是Microsoft公司为开发Windows平台下的视频应用程序提供的软件工具包,提供了一系列应用程序编程接口(API),用户可以通过它们很方便地实现视频捕获、视频编辑及视频播放等通用功能,还可利用回调函数开发更复杂的视频应用程序。它的特点是播放视频时不需要专用的硬件设备,而且应用灵活,可以满足视频应用程序开发的需要。Windows操作系统自身就携带了VFW,系统安装时,会自动安装VFW的相关组件。
下表为VFW的功能模块
模 块 |
功 能 |
AVICAP.DLL |
包含执行视频捕获的函数,它给AVI文件的I/O处理和视频、音频设备驱动程序提供一个高级接口 |
MSVIDEO.DLL |
包含一套特殊的DrawDib函数,用来处理屏幕上的视频操作 |
MCIAVI.DRV |
包括对VFW的MCI命令解释器的驱动程序 |
AVIFILE.DLL |
包含由标准多媒体I/O(mmio)函数提供的更高的命令,用来访问.AVI文件 |
ICM |
压缩管理器,用于管理的视频压缩/解压缩的编译码器(Codec) |
ACM |
音频压缩管理器,提供与ICM相似的服务,适用于波形音频 |
6.2 JMF和VFW的关系:
注意以下代码:
String str1 = "vfw:Logitech USB Video Camera:0";
String str2 = "vfw:Microsoft WDM Image Capture (Win32):0";
device = CaptureDeviceManager.getDevice(str2);
medialocator = device.getLocator();
只要是vfw开头的设备信息,就能为JMF架构识别并加以使用。可以编写代码来识别此设备。
在JMF中,当使用了 Detect Capture Devices以后,可以发现在Capture Devices多了一个设备名称:
6.3一个识别类代码及分析
private MediaLocator autoDetect(){//自动识别功能函数 MediaLocator ml = null; //视频采集设备对应的MediaLocator VideoFormat currentFormat = null;//用户定制获得视频采集设备支持的格式 Format setFormat = null;//用户定制视频采集设备输出的格式 Format[] videoFormats = null;//视频采集设备支持的所有格式 System.out.println(" AutoDetect for VFW"); //获得当前所有设备列表 Vector deviceList = CaptureDeviceManager.getDeviceList( null ); if( deviceList != null ){ //根据设备列表,找出可用设备名称 for( int i=0; i<deviceList.size(); i++ ){ try{ CaptureDeviceInfo di=( CaptureDeviceInfo )deviceList.elementAt(i); //如果设备名称以vfw开头 if( di.getName().startsWith("vfw:") ){ //获得所有支持RGB格式 videoFormats = di.getFormats(); for( int j=0; j<videoFormats.length; j++ ){ //我们只需要第一种RGB格式 if( videoFormats[j] instanceof RGBFormat ){ currentFormat = ( RGBFormat )videoFormats[i]; break; } } if( currentFormat == null ) { System.err.println("Search For RGBFormat Failed"); System.exit( -1 ); } //通过设备,获得MediaLocator,这个很重要 ml = di.getLocator(); } } catch ( Exception npe ) { System.err.println( "Unable to get Processor for device"); System.exit(-1); } } } else { System.err.println( "No Capture Device OK"); System.exit(-1); } return ml;//返回可用的设备medialocator } |