如何在不安装JMF的情况下使用JMF捕获视频

14

我曾经参与的一个视频会议项目使用JMF来捕获视频和音频,并将其传输到另一个端点。问题是,我的团队不希望产品的用户安装JMF。

我认为分享我们解决这个问题的方法可能是值得的。它能正常工作,而且效果很好。我想问一下,有没有更好的方法呢?

环境:Windows XP 及以上版本

  1. 下载 JMF for Windows
  2. 在计算机上进行安装
  3. 在 jmf 安装后,在 system32 文件夹中找到以下 dll
  4. jmacm.dll
    jmam.dll
    jmcvid.dll
    jmdaud.dll
    jmdaudc.dll
    jmddraw.dll
    jmfjawt.dll
    jmg723.dll
    jmgdi.dll
    jmgsm.dll
    jmh261.dll
    jmh263enc.dll
    jmjpeg.dll
    jmmci.dll
    jmmpa.dll
    jmmpegv.dll
    jmutil.dll
    jmvcm.dll
    jmvfw.dll
    jmvh263.dll
    jsound.dll

  5. 将这些 dll 复制到一个临时文件夹中
  6. 查找 jmf.properties 文件(在电脑上搜索它)
  7. 下载 JMF 源代码
    在源代码中,找到以下文件:

JMFinit.java
JMRPropertiesGen.java
Registry.java
RegistryGen.java

  1. 创建一个包;我称其为 JMFNoInstall
  2. 添加第 6 步中列出的文件
  3. 添加名为 Main 的类到该包中,如下所示:
package JMFNoInstall;
// add your imports and whatnot here
public class Main()
{
    public Main()
    {
        JMFinit.main(null);
        JMFPropertiesGen.main(null);
        Registry.main(null);
        RegistryGen.main(new String[] {
            new File(".").getAbsolutePath(),
            "registrylib"
        });
    }
}
jmf.properties文件需要放在包含main方法的类所在的文件夹或包含main方法的JAR归档文件所在的文件夹中。
dll文件需要放在win32文件夹中。您可以让程序检查这些文件是否位于win32文件夹中。如果不在,可以将它们从某个位置复制到此处。每次运行上面列出的Main类时,jmf.properties文件都会被更新。您只需要在程序第一次运行时运行一次,或者如果用户想要添加新的捕获设备,则需要运行一次。最后,请确保在类路径中包含Windows JMF下载附带的jmf.jar文件和jmfcom.jar文件。完成以上步骤后,即可使用JMF的所有功能,无需实际安装它。

实际上,这并不需要太多工作,而且您可以很容易地将其合并到自定义安装程序中。

但是,有没有人发现了更好的方法呢?这种做法存在一些缺陷。

编辑:我认为分享一些我创建的代码可能是值得的。当然,您需要修改它以处理您所需的内容。它可能无法编译,但缺失的内容应该很容易重新创建。但是我认为这可能是帮助人们的一个很好的起点。detectCaptureDevices函数可能是最有帮助的。我会随时更新这个类。


import GUI.Window;
import GlobalUtilities.OS;
import GlobalUtilities.ProgressBar;
import GlobalUtilities.FileUtilities;
import java.io.File;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.text.Utilities;
/** * 该类提供了对JMF最需要的信息的易于访问。您可以测试JMF安装(目前仅适用于Windows),并获取有关连接到JMF的捕获设备的信息。 */ public class JMFRunner { /** * 显示操作状态 */ final ProgressBar theBar = new ProgressBar(); /** * 存放JMF依赖的dll所需的位置 */ final String windowsDllFolder = "C:\\WINDOWS\\system32\\";
final String linuxDllFolder = "/usr/lib/";
/** * JMF使用的dll */ final String[] windowsDllList = new String[]{ "jmacm.dll", "jmam.dll", "jmcvid.dll", "jmdaud.dll", "jmdaudc.dll", "jmddraw.dll", "jmfjawt.dll", "jmg723.dll", "jmgdi.dll", "jmgsm.dll", "jmh261.dll", "jmh263enc.dll", "jmjpeg.dll", "jmmci.dll", "jmmpa.dll", "jmmpegv.dll", "jmutil.dll", "jmvcm.dll", "jmvfw.dll", "jmvh263.dll", "jsound.dll"};
String[] linuxDllList = new String[]{ "libjmcvid.so", "libjmdaud.so", "libjmfjawt.so", "libjmg723.so", "libjmgsm.so", "libjmh261.so", "libjmh263enc.so", "libjmjpeg.so", "libjmmpa.so", "libjmmpegv.so", "libjmmpx.so", "libjmutil.so", "libjmv4l.so", "libjmxlib.so" };
String [] dlls= null; String dir = null;
/** * JMF发现的视频捕获设备列表 */ Vector videoDevices = null; /** * JMF发现的音频捕获设备列表 */ Vector audioDevices = null;
public JMFRunner() { if(OS.isWindows()) { dlls = windowsDllList; dir = windowsDllFolder; } else if(OS.isLinux()) { dlls = linuxDllList; dir = linuxDllFolder; } else { Window.getLogger().severe("操作系统不支持JMF"); }
}
/** * 添加新的捕获设备 */ public void detectCaptureDecives() {
Thread theTread = new Thread(theBar); theTread.start(); theBar.repaint();
JMFInit.main(new String[] {""}); JMFPropertiesGen.main(new String[] {""}); Registry.main(new String[] {""}); RegistryGen.main(new String[] {"-d", new File(".").getAbsolutePath(), "registrylib" });
theBar.setMessage(""); theBar.stop(); }
/** * 验证JMF需要的所有dll是否位于其正确位置 * @return 如果所有dll都在正确位置,则为True,否则为False */ public boolean detectDlls() { boolean retVal = true; String currFile; for(String currDll : dlls) { currFile = dir + currDll; if(! new File(currFile).exists()) { Window.getLogger().severe("找不到JMF所需的dll文件 " + currFile); retVal = false; } } return retVal; }
//尚未正常工作 public boolean installLibraryFiles() { boolean retVal = true; String currFile; for(String currDll : dlls) { currFile = dir + currDll; File newDll = new File(currFile); //看看这个dll是否已经存在 if(!newDll.exists()) { //它不存在,让我们将其复制 try { FileUtilities.copy(newDll,FileUtilities.getResourceFile("/JMFManager/Resources/"+currDll,curr

DeviceFinder.java


import java.util.Vector;
import javax.media.*;
import javax.media.format.*;
/** * 此类获取有关捕获设备(麦克风和摄像头)的信息 */ public class DeviceFinder {
Vector videoDevices = new Vector(); Vector audioDevices = new Vector();
/** * 构造函数 * 创建新的 DeviceFinder */ public DeviceFinder() { /*检索所有视频和音频设备*/ videoDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(null)); audioDevices = CaptureDeviceManager.getDeviceList(new AudioFormat(null)); }
/** * 作用:获取系统上所有视频捕获设备的信息 * @return java.util.Vector
一个属性向量 */ public Vector getVideoCaptureDevices() { return videoDevices; }
/** * 作用:获取系统上所有音频捕获设备的信息 * @return java.util.Vector
一个属性向量 */ public Vector getSoundCaptureDevices() { return audioDevices; }
/** * 检索第一台视频捕获设备 */ public CaptureDeviceInfo getPrimaryVideoCaptureDevice() { return (CaptureDeviceInfo)videoDevices.get(0); }
/*检索第一台音频捕获设备*/ public CaptureDeviceInfo getPrimaryAudioCaptureDevice() { return (CaptureDeviceInfo)audioDevices.get(0); }
/** * 获取第一个视频设备的名称 * @return String
视频设备的名称 */ public String getVideoCaptureDeviceName() { return ((CaptureDeviceInfo)videoDevices.get(0)).getName(); }
/** * 获取第一个音频设备的名称 * @return String
音频设备的名称 */ public String getAudioCaptureDeviceName() { return ((CaptureDeviceInfo)audioDevices.get(0)).getName(); }
/** * 获取第一个视频设备的媒体定位器 * @return MediaLocator */ public MediaLocator getVideoMediaLocator() { return ((CaptureDeviceInfo)videoDevices.get(0)).getLocator(); }
/** * 获取第一个音频设备的媒体定位器 * @return MediaLocator */ public MediaLocator getAudioMediaLocator() { return ((CaptureDeviceInfo)audioDevices.get(0)).getLocator(); }
/** * 获取索引 idx 的视频设备媒体定位器(0 是第一/默认项, * 根据 JMFRegistry 排序) * @param idx 媒体定位器的索引 * @return MediaLocator */ public MediaLocator getVideoMediaLocator(int idx) { if(idx >= videoDevices.size()) { return null; } return ((CaptureDeviceInfo)videoDevices.get(idx)).getLocator(); }
/** * 获取索引 idx 的音频设备媒体定位器(根据 JMFRegistry 排序) * @param idx 音频设备的索引 * @return MediaLocator */ public MediaLocator getAudioMediaLocator(int idx) { return ((CaptureDeviceInfo)audioDevices.get(idx)).getLocator(); }
/** * * @param args */ public static void main(String[] args) { DeviceFinder df = new DeviceFinder(); //DEBUG: System.out.println(df.getVideoMediaLocator()); System.out.println(df.getAudioMediaLocator()); } }

1
@Stackfan,我已经添加了一些我的代码,如果有帮助的话。 - user489041
当你在IA 32位平台上遇到“无法加载此.dll文件(机器代码=0x0)”的错误时,他们是否不在c:\windows\system32目录下? - MikeNereson
在删除了之前运行的dll文件后,您可以看到我的控制台输出显示dll文件被写入了system32 http://pastie.org/1966273 - MikeNereson
"添加步骤5中列出的文件。确定是第5步而不是第6步吗?" - CSchulz
@user489041,我们遇到了同样的问题。您能否考虑帮助我们?这也可以是有偿咨询。这是为了一个良好的社会事业。您可以通过jeff [at] mentorstudents [dot] org联系到我。 - jeff musk
显示剩余11条评论
1个回答

4
我认为没有更好的办法。除非按路径名显式加载DLL文件,否则您仅需要确保它们位于系统路径中,因此如果它们就在JVM可执行文件旁边,那么也应该可以工作。Windows默认包含程序启动目录在系统路径中,这是另一个可能的位置。
安装程序有两面性,它们使添加新功能和稍后删除变得容易,但它们也使部署使用该产品的解决方案变得更加困难。
Java的一大优点是,您无需安装即可使用它。基本上,在一台系统上执行JRE的安装后,您可以将其打包并在另一台系统上使用zip文件。Java不需要显式注册DLL文件,因为它会根据需要动态加载它们。

1
这是非常正确的。另一方面,JMF确实需要安装。正如您所说的那样,这正是Java的一个好处,“你不需要安装它就可以使用它。”我们不希望最终用户为了使我们的应用程序工作而安装其他任何东西。如果应用程序作为小程序运行,这也是非常正确的。我们只想在幕后复制文件并使一切正常。模拟JMF的安装并不容易。有很多在幕后设置的属性。 - user489041

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接