怎样用java程序 使用摄像头 生成视频

解决方案 »

  1.   

    1.播放多媒体 在JMF.java中有一个play()方法。该方法可以播放用户选择的多媒体文件。当播放多媒体文件时,你需要一个Player对象。在例子中,dualPlayer就是Player接口的实现对象。 
    Player dualPlayer;
    在Play()方法中,通过使用FileDialog获得媒体文件的路径和文件名,并保存在filename中。  try {
        FileDialog fd = 
          new FileDialog(this, "Select File", FileDialog.LOAD);
        fd.show();
        String filename = fd.getDirectory() + fd.getFile();
        ...
      }
      catch (Exception e) {
        System.out.println(e.toString());
      }
    然后你需要通过媒体管理器Manager间接创建一个Player对象。你可以使用Manager类的createPlayer()方法或者createProcessor()方法来获得一个Player对象或Processor对象。在play()方法中,我使用的是createPlayer()方法。  dualPlayer = Manager.createPlayer
          (new MediaLocator("file:///" + filename));有时你需要使用一个Player对象来控制多个其他的Player和Controller对象,我们把这个Player对象称为主对象,并把这些对象组成一个组。通过调用主对象中的start()、stop()、setMediaTime()等方法就可以激活组中所有成员的相应方法。主对象控制所有的状态变化和事件发布。然后使用addControllerListerner()方法来将一个ControllerListener对象绑定到Player对象上,Controller对象将向该ControllerListener对象发送事件消息。  dualPlayer.addControllerListener(this);
    最后需要调用start()方法来启动Player对象。start()方法将Player对象的状态设置为Started。如果Player没有被实体化(Realize)或预取(Prefetch),start()方法会自动执行这些操作。  dualPlayer.start();
    由于JMF类实现了ControllerLister接口,因此需要实现该接口中的controllerUpdate()方法,该方法在Controller对象产生一个事件时被调用。  public synchronized void controllerUpdate(ControllerEvent event) {
      if (event instanceof RealizeCompleteEvent) {
        Component comp;
        if ((comp = dualPlayer.getVisualComponent()) != null)
          add ("Center", comp);
        if ((comp = dualPlayer.getControlPanelComponent()) != null)
          add("South", comp);
        validate();
      }
    }
    当JMF类产生了一个RealizeCompleteEvent事件后,controllerUpdate()方法在界面上增加两个Component对象,一个用于播放媒体,一个用于放置控制按钮,例如播放、停止等。 在运行程序的过程中,程序会产生下面的输出。  Starting player ...javax.media.TransitionEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Unrealized,
      current=Realizing,
      target=Started]
    Open log file: C:\test\Java\JMF\JMF\jmf.log
    javax.media.DurationUpdateEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,duration=
      javax.media.Time@2a37a6
    javax.media.RealizeCompleteEvent
    [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Realizing,
      current=Realized,
      target=Started]
    Adding visual component
    Adding control panel
    javax.media.TransitionEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Realized,
      current=Prefetching,
      target=Started]
    javax.media.PrefetchCompleteEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Prefetching,
      current=Prefetched,target=Started]
    javax.media.StartEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Prefetched,
      current=Started,
      target=Started,
      mediaTime=javax.media.Time@56a05e,timeBaseTime=
      javax.media.Time@3a8602]
    javax.media.EndOfMediaEvent
      [source=com.sun.media.content.video.mpeg.Handler@71bb78,
      previous=Started,
      current=Prefetched,
      target=Prefetched,
      mediaTime=javax.media.Time@1d332b]
    前面提到,当调用start()方法的时候,Player会切换到Started状态。从上面列出的信息中可以看到Player对象的状态从Unrealized变成了Started。当EndOfMedia事件被激活时(这时Player对象完成了媒体文件的播放),状态从Started变成了Prefetched。图二显示了程序正在播放多媒体文件时的情况。 
    图二 程序正在播放媒体文件
    2.注册音频和视频截取设备 在例子中,注册音频和视频截取设备的方法只在程序的内部注册这些设备,在程序外则不起作用。该方法的作用是当用户的计算机上存在多和音频和视频截取设备时,告诉程序因该使用哪个设备和这些设备支持的音频和视频格式。因此在进行截取处理之前需要获得设备的配置信息。在例子中,当在Configure菜单上按下Capture Device命令后,会弹出CaptureDeviceDialog对话框。如果在截取音频或视频前没有设定设备的配置,也会弹出该对话框。图三显示了该对话框。 
    图三 设备注册对话框
    让我们来看一下CaptureDeviceDialog类中的init()方法:在初始化了界面之后,通过调用CaptureDeviceManager类的getDeviceList()方法:  devices = CaptureDeviceManager.getDeviceList ( null );
    CaptureDeviceManager类使用查询机制和一个注册表来定位设备,然后将设备的信息放入CaptureDeviceInfo对象中返回。我们还可以利用CaptureDeviceManager类来注册新的设备。通过调用getDeviceList()方法程序获取了一个支持指定格式的设备的列表。在例子中,我将格式参数设定为null,这意味着设备可以使用任何格式。返回值被放入device变量中。如果getDeviceList()方法返回的是一个非空值,程序会将包含在其中的音频设备名称和视频设备名称分别放入两个下拉列表中中,但是到目前为止我们还不知道哪些设备是音频设备,哪些是视频设备。 我们可以通过CaptureDeviceInfo的getFormat()方法获得Format对象组数,在Format对象中保存了设备支持的媒体格式。Format类间接被AudioFormat和VideoFormat类所继承。因此我们可以利用设备支持的格式类型来区分设备的类型:  if (devices!=null && devices.size()>0) {
          int deviceCount = devices.size();
          audioDevices = new Vector();
          videoDevices = new Vector();
          Format[] formats;
          for ( int i = 0;  i < deviceCount;  i++ ) {
            cdi = (CaptureDeviceInfo) devices.elementAt ( i );
            formats = cdi.getFormats();
            for ( int j=0;  j<formats.length; j++ ) {
              if ( formats[j] instanceof AudioFormat ) {
                audioDevices.addElement(cdi);
                break;
              }
              else if (formats[j] instanceof VideoFormat ) {
                videoDevices.addElement(cdi);
                break;
              }
            }
          }
          . . .
        }
    上面的程序运行后,audioDevices()中将包含所有的音频设备,videoDevices()中将保存所有的视频设备。其中cdi是CaptureDeviceInfo对象。然后将设备名称填入下拉列表中:  // 将音频设备显示在下拉列表中
          for (int i=0; i<audioDevices.size(); i++) {
            cdi  = (CaptureDeviceInfo) audioDevices.elementAt(i);
            audioDeviceCombo.addItem(cdi.getName());
          }
          // 将视频设备显示在下拉列表中
          for (int i=0; i<videoDevices.size(); i++) {
            cdi  = (CaptureDeviceInfo) videoDevices.elementAt(i);
            videoDeviceCombo.addItem(cdi.getName());
          }
    然后程序显示出当前选中的设备支持的格式:  displayAudioFormats();
          displayVideoFormats();
    下一步需要获取用户选中的音频设备和视频设备以及它们支持的格式,相关的方法是JMF类中的getAudioDevice()、getVideoDevice()、getAudioFormat()和getVideoFormat()方法。然后将获取的对象分别保存到audioCDI,videoCDI,audioFormat和videoFormat中:  audioCDI = cdDialog.getAudioDevice();
        if (audioCDI!=null) {
          audioDeviceName = audioCDI.getName();
          System.out.println("Audio Device Name: " + audioDeviceName);
        }
        videoCDI = cdDialog.getVideoDevice();
        if (videoCDI!=null) {
          videoDeviceName = videoCDI.getName();
          System.out.println("Video Device Name: " + videoDeviceName);
        }
        // 获得选中的多媒体格式
        videoFormat = cdDialog.getVideoFormat();
        audioFormat = cdDialog.getAudioFormat();
    3.截取视频和音频 使用capture()方法可以截取音频和视频数据。但是在使用该方法前需要确定是否已经选中了视频和音频截取设备:  if (audioCDI==null && videoCDI==null)
         registerDevices();
    和play()方法类似,可以通过使用Manger类中的静态方法createPlayer()创建一个Player对象,该对象可以播放一个DataSource对象中的数据流。  Player createPlayer(MediaLocator sourceLocator)
    在例子中,我首先通过调用audioCDI和videoCDI的getLocator()方法来获得MediaLocator对象,然后利用Manager类的createPlayer()方法创建Player对象。最后将一个ControllerListener对象绑定到视频Player对象上并开始播放。  videoPlayer = Manager.createPlayer(videoCDI.getLocator());
            audioPlayer = Manager.createPlayer(audioCDI.getLocator());
            videoPlayer.addControllerListener(this);
            videoPlayer.start();
            audioPlayer.start();
    使用这种方法导致最后获得了两个Player对象。我们也可以使用Manager类中的createDataSource()方法从视频和音频CaptureDeviceInfo对象(audioCID和videoCDI)中获得视频和音频数据源(DataSource对象),然后调用createMergingDataSource()方法将两个数据源合并成一个数据源(ds):  DataSource[] dataSources = new DataSource[2];
            dataSources[0] =
              Manager.createDataSource(audioCDI.getLocator());
            dataSources[1] =
              Manager.createDataSource(videoCDI.getLocator());
            DataSource ds = Manager.createMergingDataSource(dataSources);
    然后可以使用ds作为createPlayer()方法的参数来获得一个Player对象dualPlayer。调用addControllerListener()就可以进行播放了。  dualPlayer = Manager.createPlayer(ds);
    dualPlayer.addControllerListener(this);
    dualPlayer.start();