[英]How to capture video using JMF, but without installing JMF
A videoconferencing project I was working on used JMF to capture video and audio, and transmit it to another endpoint. 我正在研究的视频会议项目使用JMF来捕获视频和音频,并将其传输到另一个端点。 An issue was that my team didn't want the user of the product to have to install JMF.
问题是我的团队不希望产品的用户必须安装JMF。
I thought it might be worthwhile to share our solution to this problem. 我认为分享我们对这个问题的解决方案可能是值得的。 It works.
有用。 It works well.
它运作良好。 My question to you is: does anyone have a better way to do it?
我的问题是:有没有人有更好的方法呢?
Environment: Windows, XP and above 环境:Windows,XP及以上版本
Install it on your machine 将其安装在您的机器上
Locate the following dll
s in the system32 folder after jmf installs: 在jmf安装后,在system32文件夹中找到以下
dll
:
jmacm.dll jmacm.dll
jmam.dll jmam.dll
jmcvid.dll jmcvid.dll
jmdaud.dll jmdaud.dll
jmdaudc.dll jmdaudc.dll
jmddraw.dll jmddraw.dll
jmfjawt.dll jmfjawt.dll
jmg723.dll jmg723.dll
jmgdi.dll jmgdi.dll
jmgsm.dll jmgsm.dll
jmh261.dll jmh261.dll
jmh263enc.dll jmh263enc.dll
jmjpeg.dll jmjpeg.dll
jmmci.dll jmmci.dll
jmmpa.dll jmmpa.dll
jmmpegv.dll jmmpegv.dll
jmutil.dll jmutil.dll
jmvcm.dll jmvcm.dll
jmvfw.dll jmvfw.dll
jmvh263.dll jmvh263.dll
jsound.dll jsound.dll
Copy the dll
s into a temporary folder 将
dll
复制到临时文件夹中
jmf.properties
file (Do a search on your computer for it) jmf.properties
文件(在您的计算机上搜索它) JMFinit.java JMFinit.java
JMRPropertiesGen.java JMRPropertiesGen.java
Registry.java Registry.java
RegistryGen.java RegistryGen.java
JMFNoInstall
JMFNoInstall
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"
});
}
}
The jmf.properties
file needs to go in the same folder as the class that has your main
method or the same folder as the JAR archive that contains the main
method. jmf.properties
文件需要与具有main
方法的类位于同一文件夹中,或者与包含main
方法的JAR存档位于同一文件夹中。
The dll
s need to go into the win32
folder. dll
需要进入win32
文件夹。 You can have your program check to see if they are in the win32
folder. 您可以让程序检查它们是否在
win32
文件夹中。 If they are not, you can have it copy them over from some location. 如果不是,您可以将它从某个位置复制过来。 The
jmf.properties
file gets updated whenever the the Main
class listed above runs. 只要上面列出的
Main
类运行, jmf.properties
文件就会更新。 You only need to run this once, the first time the program is ever run, or if the user would like to add new capture devices. 您只需要运行一次,第一次运行程序,或者用户是否想要添加新的捕获设备。 Lastly, just make sure the
jmf.jar
file and jmfcom.jar
that comes along with the Windows JMF download is included in the classpath. 最后,确保包含Windows JMF下载的
jmf.jar
文件和jmfcom.jar
包含在类路径中。 You're good to go at this point. 你很高兴在这一点上去。 All the functionality of JMF without actually having to install it.
JMF的所有功能,而无需实际安装它。
There really isn't a lot of work involved with this, and you can incorporate it into your custom installer quite easily. 实际上并没有涉及到很多工作,您可以很容易地将它合并到自定义安装程序中。
Has anyone found a better way to do this though? 有没有人找到更好的方法来做到这一点? There are a few pitfalls of doing it this way.
这样做有一些陷阱。
EDIT: I thought it might be worthwhile to share some of the code that I created. 编辑:我认为分享我创建的一些代码可能是值得的。 Of course youll need to modify it to handle what you.
当然你需要修改它来处理你的问题。 It prob wont compile, but the stuff that is missing should be easy enough to recreate.
它不会编译,但缺少的东西应该很容易重新创建。 But thought it might be a good starting point to help people.
但是认为这可能是帮助人们的良好起点。 The detectCaptureDevices function is probably what will help most people.
detectCaptureDevices函数可能会帮助大多数人。 Ill update this class as I go.
我去的时候会更新这门课。
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;
/**
* This class providex easy access to the most needed info about JMF. You can test
* a JMF install (Windows only currently) and also get info about the captrue
* devices hooked up to JMF.
* @author dvargo
*/
public class JMFRunner
{
/**
* Show the status of operations
*/
final ProgressBar theBar = new ProgressBar();
/**
* Location where the dll's JMF relies on need to be placed
*/
final String windowsDllFolder = "C:\\WINDOWS\\system32\\";
final String linuxDllFolder = "/usr/lib/";
/**
* Dll's that JMF uses
*/
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;
/**
* List of the video capture devices found by JMF
*/
Vector videoDevices = null;
/**
* List of the audio capture devices found by 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("Operating system does not support JMF");
}
}
/**
* Adds new capture devices
*/
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();
}
/**
* Verifies that all the dll's that JMF needs are in their correct spot
* @return True if all dlls are in their correct spot, false otherwise
*/
public boolean detectDlls()
{
boolean retVal = true;
String currFile;
for(String currDll : dlls)
{
currFile = dir + currDll;
if(! new File(currFile).exists())
{
Window.getLogger().severe("Can not find dll " + currFile + " for JMF");
retVal = false;
}
}
return retVal;
}
//Doesnt work quite yet
public boolean installLibraryFiles()
{
boolean retVal = true;
String currFile;
for(String currDll : dlls)
{
currFile = dir + currDll;
File newDll = new File(currFile);
//see if this dll is already there
if(!newDll.exists())
{
//its not there so lets copy it
try
{
FileUtilities.copy(newDll,FileUtilities.getResourceFile("/JMFManager/Resources/"+currDll,currDll));
}
catch(Exception e)
{
retVal = false;
}
}
}
return retVal;
}
/**
* Returns the location of the jmf.properties file that STix is using
* @return THe locaiton of the JMF properties
*/
public String getJMFPropertiesFileLocation()
{
return Registry.getJMFPropertiesFileLocation();
}
/**
* Returns a list of the audio devices found by JMF
* @return Returns an Arraylist containing info about the audio capture devices
*/
public ArrayList getAudioDevices()
{
DeviceFinder df = new DeviceFinder();
audioDevices = df.getSoundCaptureDevices();
return new ArrayList(audioDevices);
}
/**
* Returns a list of the video decives deteced by JMF
* @return returns an arraylist with info of the video capture devices
*/
public ArrayList getVideoDevices()
{
DeviceFinder df = new DeviceFinder();
videoDevices = df.getVideoCaptureDevices();
return new ArrayList(videoDevices);
}
public static void main(String [] args)
{
JMFRunner x = new JMFRunner();
//x.detectCaptureDecives();
x.installLibraryFiles();
System.out.println(x.detectDlls());
System.out.println(x.getJMFPropertiesFileLocation());
System.out.println(x.getAudioDevices());
System.out.println(x.getVideoDevices());
}
}
DeviceFinder.java DeviceFinder.java
import java.util.Vector;
import javax.media.*;
import javax.media.format.*;
/**
* this class gets information about capture devices (mics and cameras)
*/
public class DeviceFinder {
Vector videoDevices = new Vector();
Vector audioDevices = new Vector();
/**
* Constructor
* Creates a new DeviceFinder
*/
public DeviceFinder()
{
/*retrieve ALL video and audio devices*/
videoDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(null));
audioDevices = CaptureDeviceManager.getDeviceList(new AudioFormat(null));
}
/**
* purpose: Get information on all Video capture devices on the system
* @return java.util.Vector
a vector of attributes
*/
public Vector getVideoCaptureDevices()
{
return videoDevices;
}
/**
* purpose: Get information on all audio capture devices on the system
* @return java.util.Vector
a vector of attributes
*/
public Vector getSoundCaptureDevices()
{
return audioDevices;
}
/**
* retrieve the first video capture device
*/
public CaptureDeviceInfo getPrimaryVideoCaptureDevice()
{
return (CaptureDeviceInfo)videoDevices.get(0);
}
/*retrieve the first audio capture device*/
public CaptureDeviceInfo getPrimaryAudioCaptureDevice()
{
return (CaptureDeviceInfo)audioDevices.get(0);
}
/**
* get the first video device name
* @return String
the name of the video device
*/
public String getVideoCaptureDeviceName()
{
return ((CaptureDeviceInfo)videoDevices.get(0)).getName();
}
/**
* get the first audio device name
* @return String
the name of the audio device
*/
public String getAudioCaptureDeviceName()
{
return ((CaptureDeviceInfo)audioDevices.get(0)).getName();
}
/**
* get the first video device media locator
* @return MediaLocator
*/
public MediaLocator getVideoMediaLocator()
{
return ((CaptureDeviceInfo)videoDevices.get(0)).getLocator();
}
/**
* get the first audio device media locator
* @return MediaLocator
*/
public MediaLocator getAudioMediaLocator()
{
return ((CaptureDeviceInfo)audioDevices.get(0)).getLocator();
}
/**
* get the video device media locator at index idx
* @param idx index of the media locator (0 is the first/default,
* as ordered by
*
the JMFRegistry)
* @return MediaLocator
*/
public MediaLocator getVideoMediaLocator(int idx)
{
if(idx >= videoDevices.size())
{
return null;
}
return ((CaptureDeviceInfo)videoDevices.get(idx)).getLocator();
}
/**
* get the audio device media locator at index idx
* @param idx index of the audio device (as ordered by the JMFRegistry)
* @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());
}
}
I don't think there is a better way. 我不认为有更好的方法。 Unless the DLLs are explicitly loaded by path name, you would just need to make sure they are in the system path, so if they lived right next to the JVM executables it should also work.
除非通过路径名显式加载DLL,否则您只需要确保它们位于系统路径中,因此如果它们位于JVM可执行文件旁边,它也应该可以工作。 Windows does implicitly include the directory the program was started from in the system path, so that is another potential location.
Windows隐式包含程序从系统路径启动的目录,因此这是另一个潜在的位置。
Installers are a double edged sword, they make it easy to add new functionality and remove it later, but they also make it harder to deploy solutions that use the product. 安装程序是一把双刃剑,它们可以轻松添加新功能并在以后删除它,但它们也使得部署使用该产品的解决方案变得更加困难。
One of the nice things about Java in general is that you don't have to install it for it to work. 一般来说,Java的一个好处就是你不必安装它才能工作。 Essentially, once you perform the install of the JRE on one system, you can bundle it up and use it on another system as a zip file.
基本上,一旦您在一个系统上执行JRE的安装,您就可以将其捆绑起来并在另一个系统上作为zip文件使用它。 Java doesn't need to explicitly register the DLLs because it loads them dynamically as needed.
Java不需要显式注册DLL,因为它根据需要动态加载它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.