我正在尝试使用CaptureDeviceManager类中的#getDeviceList()方法打印出所有支持的捕获设备,并且返回的Vector的大小为0.
为什么?我有一个有效的网络摄像头 - 所以应该至少有一个。我正在运行Mac OS X Lion - 使用JMF 2.1.1e。
谢谢!
答案 0 :(得分:1)
CaptureDeviceManager.getDeviceList(格式化格式)不检测设备。而是从JMF注册表中读取的是 jmf.properties 文件。它在类路径中搜索 jmf.properties 文件。
如果您的JMF安装成功,那么类路径将被配置为包括所有相关的JMF jar和目录。 JMF安装附带了一个 jmf.properties 文件,该文件包含在JMF安装目录下的“lib”文件夹中。这意味着 jmf.properties 将由JMStudio定位,您通常会看到JMStudio应用程序正确执行。 (如果您的JMF安装在'C:\ Program Files'下,则以管理员身份运行以绕过UAC )
创建自己的应用程序以检测设备时,可能会出现上述问题。我看到了一些与同一问题有关的问题。这是因为您的应用程序的类路径可能不同,可能不包含环境类路径。在这里查看您的IDE属性。问题是 CaptureDeviceManager 无法找到 jmf.properties 文件,因为它不存在。
如您所知,您可以从JMF安装文件夹中复制 jmf.properties 文件。它将包含正确的设备列表,因为JMF在安装过程中检测到它(检查它只是为了确保无论如何)。
如果你想自己进行设备检测,那么创建一个空的jmf.properties文件并将其放在类路径中的某个位置(它可能在执行期间最初抛出一个java.io.EOFException,但是由JMF类正确处理)。然后使用以下代码检测网络摄像头......
import javax.media.*;
import java.util.*;
public static void main(String[] args) {
VFWAuto vfwObj = new VFWAuto();
Vector devices = CaptureDeviceManager.getDeviceList(null);
Enumeration deviceEnum = devices.elements();
System.out.println("Device count : " + devices.size());
while (deviceEnum.hasMoreElements()) {
CaptureDeviceInfo cdi = (CaptureDeviceInfo) deviceEnum.nextElement();
System.out.println("Device : " + cdi.getName());
}
}
下面给出了VFWAuto类的代码。这是JMStudio源代码的一部分。您可以很好地了解如何在注册表中检测和记录设备。测试时将两个类放在同一个包中。忽略VFWAuto类中的main方法。
import com.sun.media.protocol.vfw.VFWCapture;
import java.util.*;
import javax.media.*;
public class VFWAuto {
public VFWAuto() {
Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
Enumeration enum = devices.elements();
while (enum.hasMoreElements()) {
CaptureDeviceInfo cdi = (CaptureDeviceInfo) enum.nextElement();
String name = cdi.getName();
if (name.startsWith("vfw:"))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 10; i++) {
String name = VFWCapture.capGetDriverDescriptionName(i);
if (name != null && name.length() > 1) {
System.err.println("Found device " + name);
System.err.println("Querying device. Please wait...");
com.sun.media.protocol.vfw.VFWSourceStream.autoDetect(i);
nDevices++;
}
}
}
public static void main(String [] args) {
VFWAuto a = new VFWAuto();
System.exit(0);
}
}
假设您使用的是Windows平台并且有一个可用的网络摄像头,则此代码应检测设备并填充jmf.properties文件。在下一次运行中,您还可以注释掉VFWAuto部分及其对象引用,您可以看到CaptureDeviceManager从jmf.properties文件中读取。
VFWAuto类是jmf.jar的一部分。您还可以在JMStudio示例源代码中看到用于检测音频设备的DirectSoundAuto和JavaSoundAuto类。尝试使用与VFWAuto相同的方法。
我的配置是Windows 7 64位+ JMF 2.1.1e Windows性能包+网络摄像头。
答案 1 :(得分:0)
我遇到了同样的问题,我通过在flush()
对象上调用ObjectInputStream
来解决问题。
根据ObjectInputStream
的构造函数的API文档:
从流中读取包含幻数和版本号的流标头并进行验证。此方法将阻塞,直到相应的ObjectOutputStream
已写入并刷新标头。
在尝试通过套接字在两个方向上发送对象时,这是非常重要的一点,因为以错误的顺序打开流将导致死锁。
例如,考虑如果客户端和服务器在构造相应的ObjectInputStream
之前尝试从套接字的输入流构造ObjectOutputStream
会发生什么。客户端上的ObjectInputStream
构造函数将阻塞,等待幻数和版本号通过连接到达,同时服务器端的ObjectInputStream
构造函数也会因同样的原因而阻塞。因此,僵局。
因此,在打开ObjectOutputStream
之前,您应始终在代码中进行练习,以打开ObjectInputStream
并先刷新它。 ObjectOutputStream
构造函数不会阻塞,调用flush()
会强制幻数和版本号通过网络传输。如果您在客户端和服务器中都遵循这种做法,那么就不应该遇到死锁问题。
归功于Tim Rohaly和他的解释here。
答案 2 :(得分:0)
在调用CaptureDeviceManager.getDeviceList()之前,必须先将可用设备加载到内存中。
安装JMF后,可以通过运行JMFRegistry手动进行操作。
或在扩展库FMJ(Java中的Free Media)的帮助下以编程方式进行操作。这是代码:
import java.lang.reflect.Field;
import java.util.Vector;
import javax.media.*;
import javax.media.format.RGBFormat;
import net.sf.fmj.media.cdp.GlobalCaptureDevicePlugger;
public class FMJSandbox {
static {
System.setProperty("java.library.path", "D:/fmj-sf/native/win32-x86/");
try {
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
GlobalCaptureDevicePlugger.addCaptureDevices();
Vector deviceInfo = CaptureDeviceManager.getDeviceList(new RGBFormat());
System.out.println(deviceInfo.size());
for (Object obj : deviceInfo ) {
System.out.println(obj);
}
}
}
以下是输出:
USB2.0 Camera : civil:\\?\usb#vid_5986&pid_02d3&mi_00#7&584a19f&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global
RGB, -1-bit, Masks=-1:-1:-1, PixelStride=-1, LineStride=-1