Capturing Media

   

JMF capture programs are designed to capture time-based media from a live source for processing and playback. For example, audio can be captured from a microphone and a video capture card can be used to capture video from a camera. These programs usually provide controls that enable users to manage the capture process. For example, a capture control panel might provide controls that enable a user to specify the encoding type and data rate of a media stream being captured, as well as controls that allow the capture process to be started and stopped .

In essence, a capture program must determine if a certain capture device (such as a microphone and audio card, or a video camera/TV tuner and video capture card) is present before it can proceed. This is accomplished by first calling the capture device manager's getDeviceList method to return a Vector of CaptureDeviceInfo objects that correspond to a certain capture device format, and then choosing an appropriate object from this Vector .

After a capture device has been obtained, the capture program creates a processor to handle the capture process. Usually, a data sink is also created to route captured media to some kind of destination (such as a file). To demonstrate the capture of live audio from a microphone, Listing 20.7 presents source code to a CaptureDemo application.

Listing 20.7 The CaptureDemo Application Source Code
 // CaptureDemo.java import javax.media.*; import javax.media.control.*; import javax.media.datasink.*; import javax.media.format.*; import javax.media.protocol.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; class CaptureDemo extends Frame                   implements ActionListener, DataSinkListener {    StateHelper sh;    Processor processor;    DataSink filewriter = null;    CaptureDemo (String title)    {       super (title);       Panel p = new Panel ();       Button b = new Button ("Start");       b.addActionListener (this);       p.add (b);       b = new Button ("Stop");       b.addActionListener (this);       p.add (b);       add (p);       CaptureDeviceInfo di = null;       AudioFormat a = new AudioFormat (AudioFormat.LINEAR,                                        8000, 16, 1);       Vector deviceList;       deviceList = CaptureDeviceManager.getDeviceList (a);       if (deviceList.size () > 0)           di = (CaptureDeviceInfo) deviceList.firstElement ();       else           terminate ("Could not find 44,100 Hz 16-bit audio device.");       try       {           processor = Manager.createProcessor (di.getLocator ());       }       catch (IOException e)       {           terminate (e.toString ());       }       catch (NoProcessorException e)       {           terminate ("Could not find processor.");       }       // Create a helper to ensure certain states are reached.       sh = new StateHelper (processor);       // Configure the processor       if (!sh.configure (10000))           terminate ("Could not configure processor.");       // Set the output content type.       FileTypeDescriptor f;       f = new FileTypeDescriptor (FileTypeDescriptor.BASIC_AUDIO);       processor.setContentDescriptor (f);       // Realize the processor.       if (!sh.realize (10000))           terminate ("Could not realize processor.");       setSize (200, 60);       setResizable (false);       setVisible (true);    }    public void actionPerformed (ActionEvent e)    {       String cmd = e.getActionCommand ();       ((Component) e.getSource ()).setEnabled (false);       if (cmd.equals ("Start"))       {           // Get the processor's output data source.           DataSource source = processor.getDataOutput ();           // Create a File protocol MediaLocator with the location of           // the file, to which the data is to be written.           MediaLocator dest = new MediaLocator ("file:out.au");           // Create a datasink to perform file writing. Add a data           // sink listener to wait for an end of stream event. Open           // the sink to ensure that it is writable.           try           {              filewriter = Manager.createDataSink (source, dest);              filewriter.addDataSinkListener (this);              filewriter.open ();           }           catch (NoDataSinkException e2)           {              terminate ("Could not create data sink.");           }           catch (IOException e2)           {              terminate (e2.toString ());           }           // If the Processor implements StreamWriterControl, you can           // call setStreamSizeLimit to set a limit on the size of the           // file that is written.           StreamWriterControl swc = (StreamWriterControl)                         processor.getControl ("javax.media.control." +                                               "StreamWriterControl");           // Set limit to 5MB.           if (swc != null)               swc.setStreamSizeLimit (5000000);           // Start the data transfer.           try           {              filewriter.start ();           }           catch (IOException e2)           {              System.out.println (e2);           }           processor.start ();           return;       }       processor.stop ();       processor.close ();    }    public void dataSinkUpdate (DataSinkEvent e)    {       if (e instanceof EndOfStreamEvent)       {           filewriter.close ();           System.exit (0);       }    }    void terminate (String msg)    {       System.out.println (msg);       System.exit (-1);    }    public static void main (String [] args)    {       new CaptureDemo ("Capture Demo");    } } class StateHelper implements javax.media.ControllerListener {    Player player = null;    boolean configured = false;    boolean realized = false;    boolean prefetched = false;    boolean failed = false;    boolean closed = false;    public StateHelper (Player p)    {       player = p;       p.addControllerListener (this);    }           public boolean configure (int timeOutMillis)    {       long startTime = System.currentTimeMillis ();       synchronized (this)       {          if (player instanceof Processor)              ((Processor) player).configure ();          else              return false;          while (!configured && !failed)          {             try             {                 wait (timeOutMillis);             }             catch (InterruptedException ie)             {             }             if (System.currentTimeMillis () - startTime > timeOutMillis)                 break;          }       }       return configured;    }    public boolean realize (int timeOutMillis)    {       long startTime = System.currentTimeMillis ();       synchronized (this)       {          player.realize ();          while (!realized && !failed)          {             try             {                 wait (timeOutMillis);             }             catch (InterruptedException ie)             {             }             if (System.currentTimeMillis () - startTime > timeOutMillis)                 break;          }       }       return realized;    }    public boolean prefetch (int timeOutMillis)    {       long startTime = System.currentTimeMillis ();       synchronized (this)       {          player.prefetch ();          while (!prefetched && !failed)          {             try             {                 wait (timeOutMillis);             }             catch (InterruptedException ie)             {             }             if (System.currentTimeMillis () - startTime > timeOutMillis)                 break;          }       }       return prefetched && !failed;    }   public void close ()    {       synchronized (this)       {          player.close ();          while (!closed)          {             try             {                 wait (100);             }             catch (InterruptedException ie)             {             }          }       }       player.removeControllerListener (this);    }    public synchronized void controllerUpdate (ControllerEvent ce)    {       if (ce instanceof RealizeCompleteEvent)           realized = true;       else       if (ce instanceof ConfigureCompleteEvent)           configured = true;       else       if (ce instanceof PrefetchCompleteEvent)           prefetched = true;       else       if (ce instanceof ControllerErrorEvent)           failed = true;       else       if (ce instanceof ControllerClosedEvent)           closed = true;       else           return;       notifyAll();    } } 

CaptureDemo1 uses a StateHelper class to do its job. Objects created from this class (which is similar to the StateHelper class in the JMF API guide) monitor certain transition events, and help CaptureDemo1 determine when its Configured and Realized states have been reached. The approach taken by StateHelper makes use of Java's synchronization mechanism for multiple threads, together with its wait and notifyAll methods . The sole benefit is to prevent the busy-wait that was used by ProcessorDemo . (Although busy-waits are simpler, they consume microprocessor clock cycles and can slow down JVM performance.)

CaptureDemo presents a GUI that consists of a Start button and a Stop button (see Figure 20.8 ). Click Start to begin recording and Stop to finish. After Start is clicked, speak into the microphone. After Stop is clicked, CaptureDemo exits. The resulting audio is stored in a file called out.au in the current directory. Unfortunately, when tested under Windows 98, the quality of the sound capture is very poor. This is not a function of CaptureDemo , as the same poor quality results when using the JMStudio tool to capture audio.

Figure 20.8. CaptureDemo's GUI consists of Start and Stop buttons .

graphics/20fig08.gif

Note

JMStudio and another tool called JMFRegistry are included with the JMF performance pack download. JMStudio demonstrates JMF's features and JMFRegistry works with the package and plug-in managers to register package prefixes for player, processor, data source, data sink, and plug-in classes.


   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net