Java:CaptureDeviceManager#getDeviceList()是空的?

时间:2012-01-07 07:36:25

标签: java macos vector webcam jmf

我正在尝试使用CaptureDeviceManager类中的#getDeviceList()方法打印出所有支持的捕获设备,并且返回的Vector的大小为0.

为什么?我有一个有效的网络摄像头 - 所以应该至少有一个。我正在运行Mac OS X Lion - 使用JMF 2.1.1e。

谢谢!

3 个答案:

答案 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手动进行操作。

enter image description here

或在扩展库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