Как снимать видео с помощью JMF, но без установки JMF

Проект видеоконференций, над которым я работал, использовал JMF для захвата видео и аудио и передачи его на другую конечную точку. Проблема заключалась в том, что моя команда не хотела, чтобы пользователь продукта устанавливал JMF.

Я подумал, что стоит поделиться нашим решением этой проблемы. Оно работает. Это работает хорошо. Мой вопрос к вам: у кого-нибудь есть лучший способ сделать это?

Окружающая среда: Windows, XP и выше

  1. Скачать JMF для Windows
  2. Установите его на свой компьютер

  3. Найдите следующее dlls в папке system32 после установки jmf:

    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

  4. Скопируйте dlls во временную папку

  5. Найдите jmf.properties файл (выполните поиск на вашем компьютере для этого)
  6. Загрузите исходный код 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 метод или ту же папку, что и архив JAR, который содержит main метод.
dllнужно идти в win32 папка. Вы можете проверить свою программу, чтобы увидеть, находятся ли они в win32 папка. Если это не так, вы можете скопировать их из какого-либо места. jmf.properties файл обновляется всякий раз, когда Main Класс, указанный выше, работает. Вам нужно запустить его только один раз, при первом запуске программы, или если пользователь захочет добавить новые устройства захвата. Наконец, просто убедитесь, что jmf.jar файл и jmfcom.jar это идет вместе с загрузкой Windows JMF, включенной в путь к классам. Вы хорошо идти в этот момент. Вся функциональность 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;


/**
 * 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


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()); } }

1 ответ

Я не думаю, что есть лучший способ. Если библиотеки DLL не загружены явно по имени пути, вам просто нужно убедиться, что они находятся в системном пути, поэтому, если они находятся рядом с исполняемыми файлами JVM, они также должны работать. Windows неявно включает каталог, из которого была запущена программа, в системный путь, так что это еще одно потенциальное местоположение.

Установщики являются обоюдоострым мечом, они позволяют легко добавлять новые функции и удалять их позже, но они также затрудняют развертывание решений, использующих продукт.

Одна из приятных вещей о Java в целом состоит в том, что вам не нужно устанавливать ее, чтобы она работала. По сути, после выполнения установки JRE в одной системе вы можете связать ее и использовать в другой системе в виде zip-файла. Java не нужно явно регистрировать библиотеки DLL, потому что она загружает их динамически по мере необходимости.

Другие вопросы по тегам