Java/2D Graphics GUI/Media

Материал из Java эксперт
Перейти к: навигация, поиск

A Bare Bones Player: play the media object

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
/*******************************************************************************
 * A "Bare Bones" Player Applet (BBP Applet) that will play the media object
 * indicated in the "media2Play" property of the Applet tag.
 * 
 * <p>
 * The applet demonstrates the relative ease with which the JMF can be employed,
 * particularly for playing. The applet a minimal player, placing the controls
 * for the player and the visual component for the played object within the
 * Applet. The object plays once, but can be controlled by the user through the
 * control panel provided.
 * 
 * <p>
 * The tag for the Applet should look something like:
 * 
 * <!-- Sample HTML <applet code="BBPApplet.class" width=300 height=400> <param
 * name="media2Play" value="myVideo.mpg"> </applet> -->
 * 
 * @author Spike Barlow
 ******************************************************************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.media.*;
public class BBPApplet extends Applet implements ControllerListener {
  /***************************************************************************
   * Object to play the media. Only attribute that the Applet really needs.
   **************************************************************************/
  protected Player player;
  /***************************************************************************
   * The name of the media to be played.
   **************************************************************************/
  protected String nameOfMedia2Play;
  /***************************************************************************
   * Name of the Property field within the applet tage indicating the name of
   * the media to play.
   **************************************************************************/
  private static final String MEDIA_NAME_PROPERTY = "media2Play";
  /***************************************************************************
   * Object describing the location of the media to be played.
   **************************************************************************/
  protected MediaLocator locator;
  /***************************************************************************
   * Initialise the applet by attempting to create and start a Player object
   * capable of playing the media specified in the applet tag.
   **************************************************************************/
  public void init() {
    setLayout(new BorderLayout());
    setBackground(Color.lightGray);
    try {
      nameOfMedia2Play = (new URL(getDocumentBase(),
          getParameter(MEDIA_NAME_PROPERTY))).toExternalForm();
      locator = new MediaLocator(nameOfMedia2Play);
      player = Manager.createPlayer(locator);
      player.addControllerListener(this);
      player.start();
    } catch (Exception e) {
      throw new Error("Couldn"t initialise BBPApplet: " + e.getMessage());
    }
  }
  /***************************************************************************
   * Respond to ControllerEvents from the Player that was created. For the
   * bare bones player the only event of import is the RealizeCompleteEvent.
   * At that stage the visual component and controller for the Player can
   * finally be obtained and thus displayed.
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    if (e instanceof RealizeCompleteEvent) {
      add(player.getVisualComponent(), "North");
      add(player.getControlPanelComponent(), "South");
      validate();
    }
  }
}



Capture audio or video through devices connected to the PC

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/

import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import java.util.*;
/*******************************************************************************
 * A simple application to allow users to capture audio or video through devices
 * connected to the PC. Via command-line arguments the user specifies whether
 * audio (-a) or video (-v) capture, the duration of the capture (-d) in
 * seconds, and the file to write the media to (-f).
 * 
 * The application would be far more useful and versatile if it provided control
 * over the formats of the audio and video captured as well as the content type
 * of the output.
 * 
 * The class searches for capture devices that support the particular default
 * track formats: linear for audio and Cinepak for video. As a fall-back two
 * device names are hard-coded into the application as an example of how to
 * obtain DeviceInfo when a device"s name is known. The user may force the
 * application to use these names by using the -k (known devices) flag.
 * 
 * The class is static but employs the earlier Location2Location example to
 * perform all the Processor and DataSink related work. Thus the application
 * chiefly involves CaptureDevice related operations.
 * 
 * @author Michael (Spike) Barlow
 ******************************************************************************/
public class SimpleRecorder {
  /////////////////////////////////////////////////////////////
  // Names for the audio and video capture devices on the
  // author"s system. These will vary system to system but are
  // only used as a fallback.
  /////////////////////////////////////////////////////////////
  private static final String AUDIO_DEVICE_NAME = "DirectSoundCapture";
  private static final String VIDEO_DEVICE_NAME = "vfw:Microsoft WDM Image Capture:0";
  ///////////////////////////////////////////////////////////
  // Default names for the files to write the output to for
  // the case where they are not supplie by the user.
  //////////////////////////////////////////////////////////
  private static final String DEFAULT_AUDIO_NAME = "file://./captured.wav";
  private static final String DEFAULT_VIDEO_NAME = "file://./captured.avi";
  ///////////////////////////////////////////
  // Type of capture requested by the user.
  //////////////////////////////////////////
  private static final String AUDIO = "audio";
  private static final String VIDEO = "video";
  private static final String BOTH = "audio and video";
  ////////////////////////////////////////////////////////////////////
  // The only audio and video formats that the particular application
  // supports. A better program would allow user selection of formats
  // but would grow past the small example size.
  ////////////////////////////////////////////////////////////////////
  private static final Format AUDIO_FORMAT = new AudioFormat(
      AudioFormat.LINEAR);
  private static final Format VIDEO_FORMAT = new VideoFormat(
      VideoFormat.CINEPAK);
  public static void main(String[] args) {
    //////////////////////////////////////////////////////
    // Object to handle the processing and sinking of the
    // data captured from the device.
    //////////////////////////////////////////////////////
    Location2Location capture;
    /////////////////////////////////////
    // Audio and video capture devices.
    ////////////////////////////////////
    CaptureDeviceInfo audioDevice = null;
    CaptureDeviceInfo videoDevice = null;
    /////////////////////////////////////////////////////////////
    // Capture device"s "location" plus the name and location of
    // the destination.
    /////////////////////////////////////////////////////////////
    MediaLocator captureLocation = null;
    MediaLocator destinationLocation;
    String destinationName = null;
    ////////////////////////////////////////////////////////////
    // Formats the Processor (in Location2Location) must match.
    ////////////////////////////////////////////////////////////
    Format[] formats = new Format[1];
    ///////////////////////////////////////////////
    // Content type for an audio or video capture.
    //////////////////////////////////////////////
    ContentDescriptor audioContainer = new ContentDescriptor(
        FileTypeDescriptor.WAVE);
    ContentDescriptor videoContainer = new ContentDescriptor(
        FileTypeDescriptor.MSVIDEO);
    ContentDescriptor container = null;
    ////////////////////////////////////////////////////////////////////
    // Duration of recording (in seconds) and period to wait afterwards
    ///////////////////////////////////////////////////////////////////
    double duration = 10;
    int waitFor = 0;
    //////////////////////////
    // Audio or video capture?
    //////////////////////////
    String selected = AUDIO;
    ////////////////////////////////////////////////////////
    // All devices that support the format in question.
    // A means of "ensuring" the program works on different
    // machines with different capture devices.
    ////////////////////////////////////////////////////////
    Vector devices;
    //////////////////////////////////////////////////////////
    // Whether to search for capture devices that support the
    // format or use the devices whos names are already
    // known to the application.
    //////////////////////////////////////////////////////////
    boolean useKnownDevices = false;
    /////////////////////////////////////////////////////////
    // Process the command-line options as to audio or video,
    // duration, and file to save to.
    /////////////////////////////////////////////////////////
    for (int i = 0; i < args.length; i++) {
      if (args[i].equals("-d")) {
        try {
          duration = (new Double(args[++i])).doubleValue();
        } catch (NumberFormatException e) {
        }
      } else if (args[i].equals("-w")) {
        try {
          waitFor = Integer.parseInt(args[++i]);
        } catch (NumberFormatException e) {
        }
      } else if (args[i].equals("-a")) {
        selected = AUDIO;
      } else if (args[i].equals("-v")) {
        selected = VIDEO;
      } else if (args[i].equals("-b")) {
        selected = BOTH;
      } else if (args[i].equals("-f")) {
        destinationName = args[++i];
      } else if (args[i].equals("-k")) {
        useKnownDevices = true;
      } else if (args[i].equals("-h")) {
        System.out
            .println("Call as java SimpleRecorder [-a | -v | -b] [-d duration] [-f file] [-k] [-w wait]");
        System.out
            .println("\t-a\tAudio\n\t-v\tVideo\n\t-b\tBoth audio and video (system dependent)");
        System.out.println("\t-d\trecording Duration (seconds)");
        System.out
            .println("\t-f\tFile to save to\n\t-k\tuse Known device names (don"t search for devices)");
        System.out
            .println("\t-w\tWait the specified time (seconds) before abandoning capture");
        System.out
            .println("Defaults: 10 seconds, audio, and captured.wav or captured.avi, 4x recording duration wait");
        System.exit(0);
      }
    }
    /////////////////////////////////////////////////////////////////
    // Perform setup for audio capture. Includes finding a suitable
    // device, obatining its MediaLocator and setting the content
    // type.
    ////////////////////////////////////////////////////////////////
    if (selected.equals(AUDIO)) {
      devices = CaptureDeviceManager.getDeviceList(AUDIO_FORMAT);
      if (devices.size() > 0 && !useKnownDevices) {
        audioDevice = (CaptureDeviceInfo) devices.elementAt(0);
      } else
        audioDevice = CaptureDeviceManager.getDevice(AUDIO_DEVICE_NAME);
      if (audioDevice == null) {
        System.out.println("Can"t find suitable audio device. Exiting");
        System.exit(1);
      }
      captureLocation = audioDevice.getLocator();
      formats[0] = AUDIO_FORMAT;
      if (destinationName == null)
        destinationName = DEFAULT_AUDIO_NAME;
      container = audioContainer;
    }
    /////////////////////////////////////////////////////////////////
    // Perform setup for video capture. Includes finding a suitable
    // device, obatining its MediaLocator and setting the content
    // type.
    ////////////////////////////////////////////////////////////////
    else if (selected.equals(VIDEO)) {
      devices = CaptureDeviceManager.getDeviceList(VIDEO_FORMAT);
      if (devices.size() > 0 && !useKnownDevices)
        videoDevice = (CaptureDeviceInfo) devices.elementAt(0);
      else
        videoDevice = CaptureDeviceManager.getDevice(VIDEO_DEVICE_NAME);
      if (videoDevice == null) {
        System.out.println("Can"t find suitable video device. Exiting");
        System.exit(1);
      }
      captureLocation = videoDevice.getLocator();
      formats[0] = VIDEO_FORMAT;
      if (destinationName == null)
        destinationName = DEFAULT_VIDEO_NAME;
      container = videoContainer;
    } else if (selected.equals(BOTH)) {
      captureLocation = null;
      formats = new Format[2];
      formats[0] = AUDIO_FORMAT;
      formats[1] = VIDEO_FORMAT;
      container = videoContainer;
      if (destinationName == null)
        destinationName = DEFAULT_VIDEO_NAME;
    }
    ////////////////////////////////////////////////////////////////////
    // Perform all the necessary Processor and DataSink preparation via
    // the Location2Location class.
    ////////////////////////////////////////////////////////////////////
    destinationLocation = new MediaLocator(destinationName);
    System.out.println("Configuring for capture. Please wait.");
    capture = new Location2Location(captureLocation, destinationLocation,
        formats, container, 1.0);
    /////////////////////////////////////////////////////////////////////////////
    // Start the recording and tell the user. Specify the length of the
    // recording. Then wait around for up to 4-times the duration of
    // recording
    // (can take longer to sink/write the data so should wait a bit incase).
    /////////////////////////////////////////////////////////////////////////////
    System.out.println("Started recording " + duration + " seconds of "
        + selected + " ...");
    capture.setStopTime(new Time(duration));
    if (waitFor == 0)
      waitFor = (int) (4000 * duration);
    else
      waitFor *= 1000;
    int waited = capture.transfer(waitFor);
    /////////////////////////////////////////////////////////
    // Report on the success (or otherwise) of the recording.
    /////////////////////////////////////////////////////////
    int state = capture.getState();
    if (state == Location2Location.FINISHED)
      System.out.println(selected
          + " capture successful in approximately "
          + ((int) ((waited + 500) / 1000))
          + " seconds. Data written to " + destinationName);
    else if (state == Location2Location.FAILED)
      System.out.println(selected
          + " capture failed after approximately "
          + ((int) ((waited + 500) / 1000)) + " seconds");
    else {
      System.out.println(selected
          + " capture still ongoing after approximately "
          + ((int) ((waited + 500) / 1000)) + " seconds");
      System.out.println("Process likely to have failed");
    }
    System.exit(0);
  }
}



Choose the media they wish to play

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import java.awt.*;
import java.awt.event.*;
import javax.media.*;
import javax.media.protocol.*;
import javax.media.control.*;
import java.io.*;
/*******************************************************************************
 * A Graphical application allowing the user to choose the media they wish to
 * play. PlayerOfMedia presents a Dialog in which the user may enter the URL of
 * the media to play, or select a file from the local system.
 * 
 * @author Spike Barlow
 ******************************************************************************/
public class PlayerOfMedia extends Frame implements ActionListener,
    ControllerListener {
  /** Location of the media. */
  MediaLocator locator;
  /** Player for the media */
  Player player;
  /** Dialog for user to select media to play. */
  Dialog selectionDialog;
  /** Buttons on user dialog box. */
  Button cancel, open, choose;
  /** Field for user to enter media filename */
  TextField mediaName;
  /** The menus */
  MenuBar bar;
  Menu fileMenu;
  /** Dialog for informing user of errors. */
  Dialog errorDialog;
  Label errorLabel;
  Button ok;
  /** Graphical component for controlling player. */
  Component controlComponent;
  /** Graphical component showing what isbeing played. */
  Component visualComponent;
  /** Graphical component to show download progress. */
  Component progressBar;
  /** Sizes to ensure Frame is correctly sized. */
  Dimension controlSize;
  Dimension visualSize;
  int menuHeight = 50;
  /** Directory user last played a file from. */
  String lastDirectory = null;
  /** Flags indicating conditions for resizing the Frame. */
  protected static final int VISUAL = 1;
  protected static final int PROGRESS = 2;
  /***************************************************************************
   * Construct a PlayerOfMedia. The Frame will have the default title of
   * "Player of Media". All initial actions on the PlayerOfMedia object are
   * initiated through its menu (or shotcut key).
   **************************************************************************/
  PlayerOfMedia() {
    this("Player of Media");
  }
  /***************************************************************************
   * Construct a PlayerOfMedia. The Frame will have the title supplied by the
   * user. All initial actions on the PlayerOfMedia object are initiated
   * through its menu (or shotcut key).
   **************************************************************************/
  PlayerOfMedia(String name) {
    super(name);
    ///////////////////////////////////////////////////////////
    // Setup the menu system: a "File" menu with Open and Quit.
    ///////////////////////////////////////////////////////////
    bar = new MenuBar();
    fileMenu = new Menu("File");
    MenuItem openMI = new MenuItem("Open...", new MenuShortcut(
        KeyEvent.VK_O));
    openMI.setActionCommand("OPEN");
    openMI.addActionListener(this);
    fileMenu.add(openMI);
    MenuItem quitMI = new MenuItem("Quit", new MenuShortcut(KeyEvent.VK_Q));
    quitMI.addActionListener(this);
    quitMI.setActionCommand("QUIT");
    fileMenu.add(quitMI);
    bar.add(fileMenu);
    setMenuBar(bar);
    ///////////////////////////////////////////////////////
    // Layout the frame, its position on screen, and ensure
    // window closes are dealt with properly, including
    // relinquishing the resources of any Player.
    ///////////////////////////////////////////////////////
    setLayout(new BorderLayout());
    setLocation(100, 100);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        if (player != null) {
          player.stop();
          player.close();
        }
        System.exit(0);
      }
    });
    /////////////////////////////////////////////////////
    // Build the Dialog box by which the user can select
    // the media to play.
    /////////////////////////////////////////////////////
    selectionDialog = new Dialog(this, "Media Selection");
    Panel pan = new Panel();
    pan.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    mediaName = new TextField(40);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.gridwidth = 2;
    pan.add(mediaName, gbc);
    choose = new Button("Choose File...");
    gbc.ipadx = 10;
    gbc.ipady = 10;
    gbc.gridx = 2;
    gbc.gridwidth = 1;
    pan.add(choose, gbc);
    choose.addActionListener(this);
    open = new Button("Open");
    gbc.gridy = 1;
    gbc.gridx = 1;
    pan.add(open, gbc);
    open.addActionListener(this);
    cancel = new Button("Cancel");
    gbc.gridx = 2;
    pan.add(cancel, gbc);
    cancel.addActionListener(this);
    selectionDialog.add(pan);
    selectionDialog.pack();
    selectionDialog.setLocation(200, 200);
    ////////////////////////////////////////////////////
    // Build the error Dialog box by which the user can
    // be informed of any errors or problems.
    ////////////////////////////////////////////////////
    errorDialog = new Dialog(this, "Error", true);
    errorLabel = new Label("");
    errorDialog.add(errorLabel, "North");
    ok = new Button("OK");
    ok.addActionListener(this);
    errorDialog.add(ok, "South");
    errorDialog.pack();
    errorDialog.setLocation(150, 300);
    Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true));
  }
  /***************************************************************************
   * React to menu selections (quit or open) or one of the the buttons on the
   * dialog boxes.
   **************************************************************************/
  public void actionPerformed(ActionEvent e) {
    if (e.getSource() instanceof MenuItem) {
      //////////////////////////////////////////////////
      // Quit and free up any player acquired resources.
      //////////////////////////////////////////////////
      if (e.getActionCommand().equalsIgnoreCase("QUIT")) {
        if (player != null) {
          player.stop();
          player.close();
        }
        System.exit(0);
      }
      /////////////////////////////////////////////////////////
      // User to open/play media. Show the selection dialog box.
      /////////////////////////////////////////////////////////
      else if (e.getActionCommand().equalsIgnoreCase("OPEN")) {
        selectionDialog.show();
      }
    }
    //////////////////////
    // One of the Buttons.
    //////////////////////
    else {
      /////////////////////////////////////////////////////////////
      // User to browse the local file system. Popup a file dialog.
      /////////////////////////////////////////////////////////////
      if (e.getSource() == choose) {
        FileDialog choice = new FileDialog(this, "Media File Choice",
            FileDialog.LOAD);
        if (lastDirectory != null)
          choice.setDirectory(lastDirectory);
        choice.show();
        String selection = choice.getFile();
        if (selection != null) {
          lastDirectory = choice.getDirectory();
          mediaName.setText("file://" + choice.getDirectory()
              + selection);
        }
      }
      ///////////////////////////////////////////////
      // User chooses to cancel opening of new media.
      ///////////////////////////////////////////////
      else if (e.getSource() == cancel) {
        selectionDialog.hide();
      }
      ///////////////////////////////////////////////////////
      // User has selected the name of the media. Attempt to
      // create a Player.
      ///////////////////////////////////////////////////////
      else if (e.getSource() == open) {
        selectionDialog.hide();
        createAPlayer(mediaName.getText());
      }
      ////////////////////////////////////////////
      // User has seen error message. Now hide it.
      ////////////////////////////////////////////
      else if (e.getSource() == ok)
        errorDialog.hide();
    }
  }
  /***************************************************************************
   * Attempt to create a Player for the media who"s name is passed the the
   * method. If successful the object will listen to the new Player and start
   * it towards Realized.
   **************************************************************************/
  protected void createAPlayer(String nameOfMedia) {
    ////////////////////////////////////////////////////////////
    // If an existing player then stop listening to it and free
    // up its resources.
    ////////////////////////////////////////////////////////////
    if (player != null) {
      System.out.println("Stopping and closing previous player");
      player.removeControllerListener(this);
      player.stop();
      player.close();
    }
    ///////////////////////////////////////////////////////////
    // Use Manager class to create Player from a MediaLocator.
    // If exceptions are thrown then inform user and recover
    // (go no further).
    //////////////////////////////////////////////////////////
    locator = new MediaLocator(nameOfMedia);
    try {
      System.out.println("Creating player");
      player = Manager.createPlayer(locator);
    } catch (IOException ioe) {
      errorDialog("Can"t open " + nameOfMedia);
      return;
    } catch (NoPlayerException npe) {
      errorDialog("No player available for " + nameOfMedia);
      return;
    }
    //////////////////////////////////////////////////////////
    // Player created successfully. Start listening to it and
    // realize it.
    //////////////////////////////////////////////////////////
    player.addControllerListener(this);
    System.out.println("Attempting to realize player");
    player.realize();
  }
  /***************************************************************************
   * Popup a dialog box informing the user of some error. The passed argument
   * isthe text of the message.
   **************************************************************************/
  protected void errorDialog(String errorMessage) {
    errorLabel.setText(errorMessage);
    errorDialog.pack();
    errorDialog.show();
  }
  /***************************************************************************
   * Resize the Frame (window) due to the addition or removal of Components.
   **************************************************************************/
  protected void resize(int mode) {
    //////////////////////////////////////////
    // Player"s display and controls in frame.
    //////////////////////////////////////////
    if (mode == VISUAL) {
      int maxWidth = (int) Math.max(controlSize.width, visualSize.width);
      setSize(maxWidth, controlSize.height + visualSize.height
          + menuHeight);
    }
    ////////////////////////////////
    // Progress bar (only) in frame.
    ////////////////////////////////
    else if (mode == PROGRESS) {
      Dimension progressSize = progressBar.getPreferredSize();
      setSize(progressSize.width, progressSize.height + menuHeight);
    }
    validate();
  }
  /***************************************************************************
   * React to events from the player so as to drive the presentation or catch
   * any exceptions.
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    ///////////////////////////////////////
    // Events from a "dead" player. Ignore.
    ///////////////////////////////////////
    if (player == null)
      return;
    ////////////////////////////////////////////////////////////
    // Player has reached realized state. Need to tidy up any
    // download or visual components from previous player. Then
    // obtain visual and control components for the player,add
    // them to the screen and resize window appropriately.
    ////////////////////////////////////////////////////////////
    if (e instanceof RealizeCompleteEvent) {
      ////////////////////////////////////////////////////
      // Remove any inappropriate Components from display.
      ////////////////////////////////////////////////////
      if (progressBar != null) {
        remove(progressBar);
        progressBar = null;
      }
      if (controlComponent != null) {
        remove(controlComponent);
        validate();
      }
      if (visualComponent != null) {
        remove(visualComponent);
        validate();
      }
      ///////////////////////////////////////////////////////
      // Add control and visual components for new player to
      // display.
      //////////////////////////////////////////////////////
      controlComponent = player.getControlPanelComponent();
      if (controlComponent != null) {
        controlSize = controlComponent.getPreferredSize();
        add(controlComponent, "Center");
      } else
        controlSize = new Dimension(0, 0);
      visualComponent = player.getVisualComponent();
      if (visualComponent != null) {
        visualSize = visualComponent.getPreferredSize();
        add(visualComponent, "North");
      } else
        visualSize = new Dimension(0, 0);
      //////////////////////////////////////////////////////////
      // Resize frame for new components and move to prefetched.
      //////////////////////////////////////////////////////////
      resize(VISUAL);
      System.out.println("Player is now pre-fetching");
      player.prefetch();
    }
    ////////////////////////////////////////////////////////////
    // Provide user with a progress bar for "lengthy" downloads.
    ////////////////////////////////////////////////////////////
    else if (e instanceof CachingControlEvent
        && player.getState() <= Player.Realizing && progressBar == null) {
      CachingControlEvent cce = (CachingControlEvent) e;
      progressBar = cce.getCachingControl().getControlComponent();
      if (progressBar != null) {
        add(progressBar, "Center");
        resize(PROGRESS);
      }
    }
    ////////////////////////////////////////////////
    // Player initialisation complete. Start it up.
    ////////////////////////////////////////////////
    else if (e instanceof PrefetchCompleteEvent) {
      System.out.println("Pre-fetching complete, now starting");
      player.start();
    }
    ///////////////////////////////////////////////////////
    // Reached end of media. Start over from the beginning.
    ///////////////////////////////////////////////////////
    else if (e instanceof EndOfMediaEvent) {
      player.setMediaTime(new Time(0));
      System.out.println("End of Media - restarting");
      player.start();
    }
    //////////////////////////////////////////////////////////////
    // Some form of error. Free up all resources associated with
    // the player, don"t listen to it anymore, and inform the
    // user.
    //////////////////////////////////////////////////////////////
    else if (e instanceof ControllerErrorEvent) {
      player.removeControllerListener(this);
      player.stop();
      player.close();
      errorDialog("Controller Error, abandoning media");
    }
  }
  /***************************************************************************
   * Create a PlayerOfMedia object and pop it up on the screen for the user to
   * interact with.
   **************************************************************************/
  public static void main(String[] args) {
    PlayerOfMedia ourPlayer = new PlayerOfMedia();
    ourPlayer.pack();
    ourPlayer.setSize(200, 100);
    ourPlayer.show();
  }
}



Do Audio Capture

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
public class DoAudioCapture {
  public static void main(String[] args) {
    Location2Location capture;
    CaptureDeviceInfo audioDevice;
    MediaLocator audioLocation;
    MediaLocator destination;
    audioDevice = CaptureDeviceManager.getDevice("DirectSoundCapture");
    audioLocation = audioDevice.getLocator();
    Format[] format = new Format[1];
    format[0] = new AudioFormat(AudioFormat.LINEAR);
    ContentDescriptor container = new ContentDescriptor(
        FileTypeDescriptor.WAVE);
    destination = new MediaLocator(
        "file://d:\\jmf\\book\\media\\capturedSound.wav");
    capture = new Location2Location(audioLocation, destination, format,
        container, 1.0);
    System.out.println("Started recording...");
    capture.setStopTime(new Time(10.0));
    int waited = capture.transfer(35000);
    int state = capture.getState();
    System.out.println("Waited " + waited + " milliseconds. State now "
        + state);
    waited /= 1000;
    while (state != Location2Location.FINISHED
        && state != Location2Location.FAILED) {
      try {
        Thread.sleep(10000);
      } catch (InterruptedException ie) {
      }
      System.out.println("Waited another 10 seconds, state = "
          + capture.getState());
      waited += 10;
    }
    System.out.println("Waited a total of " + waited + " seconds");
    System.exit(0);
  }
}



Java Media: Find Components

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import java.awt.image.DirectColorModel;
public class FindComponents {
  DirectColorModel dcm32;
  DirectColorModel dcm16;
  int[] components;
  float[] componentsf;
  int value32;
  short value16;
  int red8, green8, blue8, alpha8;
  short red5, green5, blue5;
  /**
   * FindComponents.java -- prints out normalized color components for two
   * different
   */
  public FindComponents() {
    red8 = red5 = 30;
    green8 = green5 = 20;
    blue8 = blue5 = 10;
    alpha8 = 255;
    dcm32 = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff,
        0xff000000);
    value32 = (alpha8 << 24) + (red8 << 16) + (green8 << 8) + blue8;
    components = dcm32.getComponents(value32, null, 0);
    componentsf = dcm32.getNormalizedComponents(components, 0, null, 0);
    System.out.println("Normalized components are: ");
    for (int i = 0; i < componentsf.length; i++)
      System.out.println("\t" + componentsf[i]);
    dcm16 = new DirectColorModel(16, 0x7c00, 0x3e0, 0x1f);
    value16 = (short) ((red5 << 10) + (green5 << 5) + blue5);
    components = dcm16.getComponents(value16, null, 0);
    componentsf = dcm16.getNormalizedComponents(components, 0, null, 0);
    System.out.println("Normalized components are: ");
    for (int i = 0; i < componentsf.length; i++)
      System.out.println("\t" + componentsf[i]);
  }
  public static void main(String[] args) {
    new FindComponents();
  }
}



List all capture devices currently known to the JMF

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import javax.media.*;
import java.util.*;
/*******************************************************************************
 * Simple application to list all capture devices currently known to the JMF.
 * The CaptureDeviceManager is queried as to known devices and its output
 * printed to the screen.
 * 
 * @author Michael (Spike) Barlow
 ******************************************************************************/
public class ListCaptureDevices {
  public static void main(String[] args) {
    /////////////////////////////////////////////////////////////
    // Query CaptureDeviceManager about ANY capture devices (null
    // format)
    Vector info = CaptureDeviceManager.getDeviceList(null);
    if (info == null)
      System.out.println("No Capture devices known to JMF");
    else {
      System.out.println("The following " + info.size()
          + " capture devices are known to the JMF");
      for (int i = 0; i < info.size(); i++)
        System.out
            .println("\t" + (CaptureDeviceInfo) info.elementAt(i));
    }
  }
}



Play the media object

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
/*******************************************************************************
 * A "Bare Bones" Player Applet (BBP Applet) that will play the media object
 * indicated in the "media2Play" property of the Applet tag.
 * 
 * <p>
 * The applet demonstrates the relative ease with which the JMF can be employed,
 * particularly for playing. The applet a minimal player, placing the controls
 * for the player and the visual component for the played object within the
 * Applet. The object plays once, but can be controlled by the user through the
 * control panel provided.
 * 
 * <p>
 * The tag for the Applet should look something like:
 * 
 * <!-- Sample HTML <applet code="BBPApplet.class" width=300 height=400> <param
 * name="media2Play" value="myVideo.mpg"> </applet> -->
 * 
 * @author Spike Barlow
 ******************************************************************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.media.*;
public class TimedPApplet extends Applet implements ControllerListener {
  /***************************************************************************
   * Object to play the media. Only attribute that the Applet really needs.
   **************************************************************************/
  protected Player player;
  /***************************************************************************
   * The name of the media to be played.
   **************************************************************************/
  protected String nameOfMedia2Play;
  /***************************************************************************
   * Name of the Property field within the applet tage indicating the name of
   * the media to play.
   **************************************************************************/
  private static final String MEDIA_NAME_PROPERTY = "media2Play";
  /***************************************************************************
   * Object describing the location of the media to be played.
   **************************************************************************/
  protected MediaLocator locator;
  protected SystemTimeBase timer;
  /***************************************************************************
   * Initialise the applet by attempting to create and start a Player object
   * capable of playing the media specified in the applet tag.
   **************************************************************************/
  public void init() {
    setLayout(new BorderLayout());
    setBackground(Color.lightGray);
    try {
      nameOfMedia2Play = (new URL(getDocumentBase(),
          getParameter(MEDIA_NAME_PROPERTY))).toExternalForm();
      locator = new MediaLocator(nameOfMedia2Play);
      player = Manager.createPlayer(locator);
      player.addControllerListener(this);
      timer = new SystemTimeBase();
      player.start();
    } catch (Exception e) {
      throw new Error("Couldn"t initialise BBPApplet: " + e.getMessage());
    }
  }
  /***************************************************************************
   * Respond to ControllerEvents from the Player that was created. For the
   * bare bones player the only event of import is the RealizeCompleteEvent.
   * At that stage the visual component and controller for the Player can
   * finally be obtained and thus displayed.
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    System.out.println("" + (double) timer.getNanoseconds()
        / Time.ONE_SECOND + ": " + e);
    if (e instanceof RealizeCompleteEvent) {
      add(player.getVisualComponent(), "North");
      add(player.getControlPanelComponent(), "South");
      validate();
    }
  }
}



Play the media object 3

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
/*******************************************************************************
 * A "Bare Bones" Player Applet (BBP Applet) that will play the media object
 * indicated in the "media2Play" property of the Applet tag.
 * 
 * <p>
 * The applet demonstrates the relative ease with which the JMF can be employed,
 * particularly for playing. The applet a minimal player, placing the controls
 * for the player and the visual component for the played object within the
 * Applet. The object plays once, but can be controlled by the user through the
 * control panel provided.
 * 
 * <p>
 * The tag for the Applet should look something like:
 * 
 * <!-- Sample HTML <applet code="BBPApplet.class" width=300 height=400> <param
 * name="media2Play" value="myVideo.mpg"> </applet> -->
 * 
 * @author Spike Barlow
 ******************************************************************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.control.*;
public class ControlQueryPApplet extends Applet implements ControllerListener {
  /***************************************************************************
   * Object to play the media. Only attribute that the Applet really needs.
   **************************************************************************/
  protected Player player;
  /***************************************************************************
   * The name of the media to be played.
   **************************************************************************/
  protected String nameOfMedia2Play;
  /***************************************************************************
   * Name of the Property field within the applet tage indicating the name of
   * the media to play.
   **************************************************************************/
  private static final String MEDIA_NAME_PROPERTY = "media2Play";
  /***************************************************************************
   * Object describing the location of the media to be played.
   **************************************************************************/
  protected MediaLocator locator;
  protected SystemTimeBase timer;
  /***************************************************************************
   * Initialise the applet by attempting to create and start a Player object
   * capable of playing the media specified in the applet tag.
   **************************************************************************/
  public void init() {
    setLayout(new BorderLayout());
    setBackground(Color.lightGray);
    try {
      nameOfMedia2Play = (new URL(getDocumentBase(),
          getParameter(MEDIA_NAME_PROPERTY))).toExternalForm();
      locator = new MediaLocator(nameOfMedia2Play);
      Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true));
      player = Manager.createPlayer(locator);
      player.addControllerListener(this);
      timer = new SystemTimeBase();
      player.start();
    } catch (Exception e) {
      throw new Error("Couldn"t initialise BBPApplet: " + e.getMessage());
    }
  }
  /***************************************************************************
   * Respond to ControllerEvents from the Player that was created. For the
   * bare bones player the only event of import is the RealizeCompleteEvent.
   * At that stage the visual component and controller for the Player can
   * finally be obtained and thus displayed.
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    if (e instanceof RealizeCompleteEvent) {
      Control[] allControls = player.getControls();
      System.out.println("" + allControls.length
          + " controls for a Player @ REALIZED:");
      for (int i = 0; i < allControls.length; i++)
        System.out.println("" + (i + 1) + ": " + allControls[i]);
      add(player.getVisualComponent(), "North");
      add(player.getControlPanelComponent(), "South");
      validate();
    } else if (e instanceof StartEvent) {
      Control[] allControls = player.getControls();
      System.out.println("" + allControls.length
          + " controls for a Player @ START:");
      Panel panel = new Panel();
      for (int i = 0; i < allControls.length; i++) {
        System.out.println("" + (i + 1) + ": " + allControls[i]);
        Component cont = allControls[i].getControlComponent();
        if (cont != null) {
          System.out.println("Has a graphical component");
          panel.add(cont);
        }
      }
      panel.validate();
      add(panel, "Center");
      validate();
      FrameGrabbingControl frameControl = (FrameGrabbingControl) player
          .getControl("javax.media.control.FrameGrabbingControl");
      if (frameControl == null)
        System.out.println("Unable to obtain FrameRateControl");
      else {
        System.out.println("Have Frame Rate control");
        panel.add(frameControl.getControlComponent());
        panel.validate();
      }
    }
  }
}



Query the manager class about the configuration and support of JMF

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
/*******************************************************************************
 * ManagerQuery - Query the manager class about the configuration and support of
 * the installed JMF version. ManagerQuery is a text-based application that
 * provides a report on the support of the JMF for Players, Processors and
 * DataSinks.
 * 
 * Without any command-line arguments ManagerQuery prints a complete (LONG) list
 * of Player, Processor, and DataSource classes that support the various
 * formats, protocols, and content types.
 * 
 * Alternatively it is possible to provide command-line arguments specifying the
 * format or protocol for which support is to be checked. The means of calling
 * is as follows: java ManagerQuery [ [-h|-p|-d] support1 support2 ... supportN]
 * The -h flag specifies handlers (Players) only. The -p flag specifies
 * Processors only. The -d flag specifies DataSources only. Leaving off the flag
 * defaults behaviour to checking for Players only.
 * 
 * For instance: java ManagerQuery -h mp3 ulaw would list the classes capable of
 * Playing the MP3 (MPEG, Layer 3) and U-Law formats (codecs).
 * 
 * ManagerQuery always prints the version of JMF, caching directory, and hints
 * prior to any other output.
 * 
 * @author Spike Barlow
 ******************************************************************************/
import javax.media.*;
import javax.media.protocol.*;
import javax.media.format.*;
import java.util.*;
public class ManagerQuery {
  ///////////////////////////////////////////////////
  // Constants to facilitate selection of the
  // approprite get*List() method.
  ///////////////////////////////////////////////////
  public static final int HANDLERS = 1;
  public static final int PROCESSORS = 2;
  public static final int DATASOURCES = 3;
  ///////////////////////////////////////////////////////
  // Array containing all the content types that JMF2.1.1
  // supports. This is used when the user provides no
  // command-line arguments in order to generate a
  // complete list of support for all the content types.
  /////////////////////////////////////////////////////////
  private static final String[] CONTENTS = {
      ContentDescriptor.CONTENT_UNKNOWN, ContentDescriptor.MIXED,
      ContentDescriptor.RAW, ContentDescriptor.RAW_RTP,
      FileTypeDescriptor.AIFF, FileTypeDescriptor.BASIC_AUDIO,
      FileTypeDescriptor.GSM, FileTypeDescriptor.MIDI,
      FileTypeDescriptor.MPEG, FileTypeDescriptor.MPEG_AUDIO,
      FileTypeDescriptor.MSVIDEO, FileTypeDescriptor.QUICKTIME,
      FileTypeDescriptor.RMF, FileTypeDescriptor.VIVO,
      FileTypeDescriptor.WAVE, VideoFormat.CINEPAK, VideoFormat.H261,
      VideoFormat.H263, VideoFormat.H261_RTP, VideoFormat.H263_RTP,
      VideoFormat.INDEO32, VideoFormat.INDEO41, VideoFormat.INDEO50,
      VideoFormat.IRGB, VideoFormat.JPEG, VideoFormat.JPEG_RTP,
      VideoFormat.MJPEGA, VideoFormat.MJPEGB, VideoFormat.MJPG,
      VideoFormat.MPEG_RTP, VideoFormat.RGB, VideoFormat.RLE,
      VideoFormat.SMC, VideoFormat.YUV, AudioFormat.ALAW,
      AudioFormat.DOLBYAC3, AudioFormat.DVI, AudioFormat.DVI_RTP,
      AudioFormat.G723, AudioFormat.G723_RTP, AudioFormat.G728,
      AudioFormat.G728_RTP, AudioFormat.G729, AudioFormat.G729_RTP,
      AudioFormat.G729A, AudioFormat.G729A_RTP, AudioFormat.GSM,
      AudioFormat.GSM_MS, AudioFormat.GSM_RTP, AudioFormat.IMA4,
      AudioFormat.IMA4_MS, AudioFormat.LINEAR, AudioFormat.MAC3,
      AudioFormat.MAC6, AudioFormat.MPEG, AudioFormat.MPEG_RTP,
      AudioFormat.MPEGLAYER3, AudioFormat.MSADPCM, AudioFormat.MSNAUDIO,
      AudioFormat.MSRT24, AudioFormat.TRUESPEECH, AudioFormat.ULAW,
      AudioFormat.ULAW_RTP, AudioFormat.VOXWAREAC10,
      AudioFormat.VOXWAREAC16, AudioFormat.VOXWAREAC20,
      AudioFormat.VOXWAREAC8, AudioFormat.VOXWAREMETASOUND,
      AudioFormat.VOXWAREMETAVOICE, AudioFormat.VOXWARERT29H,
      AudioFormat.VOXWARETQ40, AudioFormat.VOXWARETQ60,
      AudioFormat.VOXWAREVR12, AudioFormat.VOXWAREVR18 };
  ////////////////////////////////////
  // The protocols that JMF supports.
  ///////////////////////////////////
  private static final String[] PROTOCOLS = { "ftp", "file", "rtp", "http" };
  /***************************************************************************
   * Return a String being a list of all hints settings.
   **************************************************************************/
  public static String getHints() {
    return "\tSecurity: " + Manager.getHint(Manager.MAX_SECURITY)
        + "\n\tCaching: " + Manager.getHint(Manager.CACHING)
        + "\n\tLightweight Renderer: "
        + Manager.getHint(Manager.LIGHTWEIGHT_RENDERER)
        + "\n\tPlug-in Player: "
        + Manager.getHint(Manager.PLUGIN_PLAYER);
  }
  /***************************************************************************
   * Produce a list of all classes that support the content types or protocols
   * passed to the method. The list is returned as a formatted String, while
   * the 2nd parameter (which) specifies whether it is Player (Handler),
   * Processor, or DataSource classes.
   **************************************************************************/
  public static String getHandlersOrProcessors(String[] contents, int which) {
    String str = "";
    Vector classes;
    int NUM_PER_LINE = 2;
    String LEADING = "\t    ";
    String SEPARATOR = "  ";
    if (contents == null)
      return null;
    /////////////////////////////////////////////////////////////////////
    // Generate a separate list for each content-type/protocol specified.
    /////////////////////////////////////////////////////////////////////
    for (int i = 0; i < contents.length; i++) {
      str = str + "\t" + contents[i] + ":\n";
      if (which == HANDLERS)
        classes = Manager.getHandlerClassList(contents[i]);
      else if (which == PROCESSORS)
        classes = Manager.getProcessorClassList(contents[i]);
      else
        classes = Manager.getDataSourceList(contents[i]);
      if (classes == null)
        str = str + "\t    <None>\n";
      else
        str = str + formatVectorStrings(classes, LEADING, 2, SEPARATOR);
    }
    return str;
  }
  /***************************************************************************
   * Get a list of all Handler (Player) classes that support each of the
   * formats (content types).
   **************************************************************************/
  public static String getHandlers() {
    return getHandlersOrProcessors(CONTENTS, HANDLERS);
  }
  /***************************************************************************
   * Get a list of all Processor classes that support each of the formats
   * (content types).
   **************************************************************************/
  public static String getProcessors() {
    return getHandlersOrProcessors(CONTENTS, PROCESSORS);
  }
  /***************************************************************************
   * Get a list of all DataSources classes that support each of the protocols.
   **************************************************************************/
  public static String getDataSources() {
    return getHandlersOrProcessors(PROTOCOLS, DATASOURCES);
  }
  /***************************************************************************
   * Format the Vector of Strings returned by the get*List() methods into a
   * single String. A simple formatting method.
   **************************************************************************/
  public static String formatVectorStrings(Vector vec, String leading,
      int count, String separator) {
    String str = leading;
    for (int i = 0; i < vec.size(); i++) {
      str = str + (String) vec.elementAt(i);
      if ((i + 1) == vec.size())
        str = str + "\n";
      else if ((i + 1) % count == 0)
        str = str + "\n" + leading;
      else
        str = str + separator;
    }
    return str;
  }
  /***************************************************************************
   * Produce a list showing total support (i.e., Player, Processors, and
   * DataSinks) for all content types and protocols.
   **************************************************************************/
  public static void printTotalList() {
    System.out.println("\nPlayer Handler Classes:");
    System.out.println(getHandlers());
    System.out.println("\nProcessor Class List:");
    System.out.println(getProcessors());
    System.out.println("\nDataSink Class List: ");
    System.out.println(getDataSources());
  }
  /***************************************************************************
   * Main method. Produce a version and hints report. Then if no command line
   * arguments produce a total class list report. Otherwise process the
   * command line arguments and produce a report on their basis only.
   **************************************************************************/
  public static void main(String args[]) {
    System.out.println("JMF: " + Manager.getVersion());
    String cacheArea = Manager.getCacheDirectory();
    if (cacheArea == null)
      System.out.println("No cache directory specified.");
    else
      System.out.println("Cache Directory: " + cacheArea);
    System.out.println("Hints:");
    System.out.println(getHints());
    // No command-line arguments. Make a toral report.
    if (args == null || args.length == 0)
      printTotalList();
    else {
      // Command-line. Process flags and then support to be
      // queried upon in order to generate appropriate report.
      String header = "";
      int whichCategory = 0;
      String[] interested;
      int i;
      int start;
      if (args[0].equalsIgnoreCase("-h")) {
        header = "\nPlayer Handler Classes: ";
        whichCategory = HANDLERS;
      } else if (args[0].equalsIgnoreCase("-p")) {
        header = "\nProcessor Class List:";
        whichCategory = PROCESSORS;
      } else if (args[0].equalsIgnoreCase("-d")) {
        header = "\nDataSink Class List: ";
        whichCategory = DATASOURCES;
      }
      if (whichCategory == 0) {
        whichCategory = HANDLERS;
        header = "\nPlayer Handler Classes: ";
        interested = new String[args.length];
        start = 0;
      } else {
        interested = new String[args.length - 1];
        start = 1;
      }
      for (i = start; i < args.length; i++)
        interested[i - start] = args[i];
      System.out.println(header);
      System.out.println(getHandlersOrProcessors(interested,
          whichCategory));
    }
  }
}



Show the Location2Location class in action

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import javax.media.*;
import javax.media.protocol.*;
import javax.media.format.*;
/*******************************************************************************
 * Simple example to show the Location2Location class in action. The
 * Location2Location class transfer media from one location to another
 * performing any requested tanscoding (format changes) at the same time.
 * 
 * The class is used twice. Once to transform a short wave audio file of an
 * electric guitar (guitar.wav) into MP3 format. The second example converts of
 * Quicktime version of the example video from chapter 7, encoded with the Indeo
 * 5.o codec and GSM audio into an AVI version with Cinepak codec for the video
 * and linear encoding for the audio.
 ******************************************************************************/
public class StaticTranscode {
  public static void main(String[] args) {
    String src;
    String dest;
    Format[] formats;
    ContentDescriptor container;
    int waited;
    Location2Location dupe;
    /////////////////////////////////////////////////////////////////
    // Transcode a wave audio file into an MP3 file, transferring it
    // to a new location (dest) at the same time.
    ////////////////////////////////////////////////////////////////
    src = "file://d:\\jmf\\book\\media\\guitar.wav";
    dest = "file://d:\\jmf\\book\\media\\guitar.mp3";
    formats = new Format[1];
    formats[0] = new AudioFormat(AudioFormat.MPEGLAYER3);
    container = new FileTypeDescriptor(FileTypeDescriptor.MPEG_AUDIO);
    dupe = new Location2Location(src, dest, formats, container);
    System.out.println("After creation, state = " + dupe.getStateName());
    waited = dupe.transfer(10000);
    System.out.println("Waited " + waited + " milliseconds. State is now "
        + dupe.getStateName());
    ///////////////////////////////////////////////////////////////////
    // Transcode a Quicktime version of a movie into an AVI version.
    // The video codec is altered from Indeo5.0 to Cinepak,the audio
    // track is transcoded from GSM to linear, and is result is saved
    // as a file "qaz.avi".
    //////////////////////////////////////////////////////////////////
    src = "file://d:\\jmf\\book\\media\\videoexample\\iv50_320x240.mov";
    dest = "file://d:\\jmf\\book\\media\\qaz.avi";
    formats = new Format[2];
    formats[0] = new VideoFormat(VideoFormat.CINEPAK);
    formats[1] = new AudioFormat(AudioFormat.LINEAR);
    container = new FileTypeDescriptor(FileTypeDescriptor.MSVIDEO);
    dupe = new Location2Location(src, dest, formats, container, 5.0f);
    System.out.println("After creation, state = " + dupe.getStateName());
    waited = dupe.transfer(Location2Location.INDEFINITE);
    int state = dupe.getState();
    System.out.println("Waited " + (waited / 1000)
        + " seconds. State is now " + dupe.getStateName()
        + ", rate was " + dupe.getRate());
    System.exit(0);
  }
}



Statistics about the tracks that compose a media object

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/
import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
/*******************************************************************************
 * A Class to determine statistics about the tracks that compose a media object.
 * Given the name (URL/location) of media a Processor is constructed and brought
 * to the Configured state. At that stage its TrackControls are obtained as a
 * means of discovering the Formats of the individual tracks.
 * 
 * Because reaching Configured can take time, the MediaStatistics object keeps
 * track of its own state and provides methods for determining that state. Only
 * when it reaches the KNOWN state can statistics be obtained. Similarly there
 * are 2 constructors: one creating a Processor and starting it toward
 * Configured but returning immediately. The other is a blocking constructor, it
 * won"t return until the Processor reaches Configured or the specified time-out
 * expires. This has the advantage that the object can be used immediately
 * (rather than polling it to determine when it enters the KNOWN state.
 * 
 * The chief information gathering method is getReport() which returns a String
 * reporting on the Format of all tracks of the media. Alternatively the Format
 * of individual tracks can also be ascertained.
 * 
 * @author Spike Barlow
 ******************************************************************************/
public class MediaStatistics implements ControllerListener {
  /** State: Yet to create the Processor. */
  public static final int NOT_CREATED = 0;
  /** State: Unable to create the Processor. */
  public static final int FAILED = -1;
  /** State: Processor is Configuring. */
  public static final int CONFIGURING = 1;
  /** State: Details of media are Known. */
  public static final int KNOWN = 2;
  /** Number of tracks is Unknown. */
  public static final int UNKNOWN = Integer.MIN_VALUE;
  /**
   * Period in milliseconds to sleep for before rechecking if reached KNOWN
   * state.
   */
  protected static final int WAIT_INTERVAL = 20;
  /** Number of tracks possessed by the media. */
  protected int numTracks = UNKNOWN;
  /** Formats of the individual tracks. */
  protected Format[] trackFormats;
  /** Processor needed to ascertain track information. */
  protected Processor processor;
  /**
   * State that the object is currently in. A reflection of the state the
   * Processor is in.
   */
  protected int state = NOT_CREATED;
  /** The name of the media on which stats are being compiled. */
  protected String nameOfMedia;
  /***************************************************************************
   * Construct a MediaStatistics object for the media with the passed name.
   * This is a blocking constructor. It returns only when it is possible to
   * obtain the track statistics or when the specified time-out period (in
   * milliseconds) has transpired.
   **************************************************************************/
  MediaStatistics(String mediaName, int timeOutInMilliseconds) {
    nameOfMedia = mediaName;
    // Construct the Processor
    try {
      MediaLocator locator = new MediaLocator(mediaName);
      processor = Manager.createProcessor(locator);
    }
    // Any exception is a failure.
    catch (Exception e) {
      state = FAILED;
      return;
    }
    // Listen to and start configuration of the Processor.
    processor.addControllerListener(this);
    state = CONFIGURING;
    processor.configure();
    //////////////////////////////////////////////////////////
    // Wait till the Processor reaches configured (the object
    // reaches KNOWN) or the specified time-out interval has
    // transpired, by looping, sleeping,and rechecking.
    //////////////////////////////////////////////////////////
    if (timeOutInMilliseconds > 0) {
      int waitTime = 0;
      while (waitTime < timeOutInMilliseconds && !isKnown()) {
        try {
          Thread.sleep(WAIT_INTERVAL);
        } catch (InterruptedException ie) {
        }
        waitTime += WAIT_INTERVAL;
      }
    }
  }
  /***************************************************************************
   * Construct a MediaStatistics object for the media with the passed name.
   * This is not a blocking constructor: it returns immediately. Thus calling
   * getReport() immediately may result in "Still parsing media" report. The
   * isKnown() method should be used to check for this condition.
   **************************************************************************/
  MediaStatistics(String mediaName) {
    this(mediaName, -1);
  }
  /***************************************************************************
   * Respond to events from the Porcessor. In particular the ConfigureComplete
   * event is the only one of interest. In this case obtain the TrackControls
   * anduse these to obtain the Formats of each track. Also modify the state
   * and close down the Processor (free up its resources).
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    if (e instanceof ConfigureCompleteEvent) {
      TrackControl[] controls = processor.getTrackControls();
      // As long as there are TrackControls, get each track"s format.
      if (controls.length != 0) {
        numTracks = controls.length;
        trackFormats = new Format[controls.length];
        for (int i = 0; i < controls.length; i++) {
          trackFormats[i] = controls[i].getFormat();
        }
        state = KNOWN;
      } else {
        state = FAILED;
      }
      // Close down the Processor.
      processor.removeControllerListener(this);
      processor.close();
      processor = null;
    }
  }
  /***************************************************************************
   * Determine what state the object is in. Returns one of the class constants
   * such as KNOWN, FAILED or CONFIGURING.
   **************************************************************************/
  public int getState() {
    return state;
  }
  /***************************************************************************
   * Determine the number of tracks possessed by the media. If that is
   * unknown, either due to the processor creation failing or because the
   * processor is not yet Configured then the class constant UNKNOWN is
   * returned.
   **************************************************************************/
  public int getNumTracks() {
    return numTracks;
  }
  /***************************************************************************
   * Obtain the Format for the specified track number. If the track doesn"t
   * exist, or it has yet to be determined how many tracks the media
   * possesses, null is returned.
   **************************************************************************/
  public Format getTrackFormat(int track) {
    if (track < 0 || track >= numTracks)
      return null;
    return trackFormats[track];
  }
  /***************************************************************************
   * Is the object in the KNOWN state? The KNOWN state reflects the fact that
   * information is known about the number and Format of the tracks. The
   * method can be used to ascertain whether a report is available
   * (meaningful) or not.
   **************************************************************************/
  public boolean isKnown() {
    return state == KNOWN;
  }
  /***************************************************************************
   * Returns true if the specified track number is an audio track. If the
   * track doesn"t exist, the number of tracks is yet unknown, or it isn"t
   * audio then false is returned.
   **************************************************************************/
  public boolean isAudioTrack(int track) {
    if (track < 0 || track >= numTracks)
      return false;
    return trackFormats[track] instanceof AudioFormat;
  }
  /***************************************************************************
   * Returns true if the specified track number is a video track. If the track
   * doesn"t exist, the number of tracks is yet unknown, or it isn"t video
   * then false is returned.
   **************************************************************************/
  public boolean isVideoTrack(int track) {
    if (track < 0 || track >= numTracks)
      return false;
    return trackFormats[track] instanceof VideoFormat;
  }
  /***************************************************************************
   * Returns a report, as a String, detailing thenumber and format of the
   * individual tracks that compose the media that this object obtained
   * statistics for. If the object is not in the KNOWN state then the report
   * is a simple String, indicating this.
   **************************************************************************/
  public String getReport() {
    String mess;
    if (state == FAILED)
      return "Unable to Handle Media " + nameOfMedia;
    else if (state == CONFIGURING)
      return "Still Parsing Media " + nameOfMedia;
    else if (state == KNOWN) {
      if (numTracks == 1)
        mess = nameOfMedia + ": 1 Track\n";
      else
        mess = nameOfMedia + ": " + numTracks + " Tracks\n";
      for (int i = 0; i < numTracks; i++) {
        if (trackFormats[i] instanceof AudioFormat)
          mess += "\t" + (i + 1) + " [Audio]: ";
        else if (trackFormats[i] instanceof VideoFormat)
          mess += "\t" + (i + 1) + " [Video]: ";
        else
          mess += "\t" + (i + 1) + " [Unknown]: ";
        mess += trackFormats[i].toString() + "\n";
      }
      return mess;
    } else
      return "Unknown State in Processing " + nameOfMedia;
  }
  /***************************************************************************
   * Simple main method to exercise the class. Takes command line arguments
   * and constructs MediaStatistics objects for them, before generating a
   * report on them.
   **************************************************************************/
  public static void main(String[] args) {
    MediaStatistics[] stats = new MediaStatistics[args.length];
    for (int i = 0; i < args.length; i++) {
      stats[i] = new MediaStatistics(args[i], 200);
      System.out.println(stats[i].getReport());
      stats[i] = null;
    }
    System.exit(0);
  }
}



Transfer media from one location to another carrying out the specified

/*
Java Media APIs: Cross-Platform Imaging, Media and Visualization
Alejandro Terrazas
Sams, Published November 2002, 
ISBN 0672320940
*/

import javax.media.*;
import javax.media.datasink.*;
import javax.media.protocol.*;
/*******************************************************************************
 * Transfer media from one location to another carrying out the specified
 * transcoding (track formats and content type) at the same time.
 * <p>
 * Users specify a source and destination location, the Formats (to be realised)
 * of the individual tracks, and a ContentDescriptor (content type) for output.
 * <p>
 * A Processor is created to perform and transcoding and its output DataSource
 * is employed to construct a DataSink in order to complete the transfer.
 * <p>
 * The most important method of the class is transfer() as this opens and starts
 * the DataSink. The constructor builds both the Processor (which is starts) and
 * the DataSink.
 * <p>
 * The object keeps track of its own state, which can be queried with the
 * getState() method. Defined constants are FAILED, TRANSLATING, TRANSFERRING,
 * and FINISHED. The process is asychronous: transcoding largish movies can take
 * a long time. The calling code should make allowances for that.
 ******************************************************************************/
public class Location2Location implements ControllerListener {
  /** Output of the Processor: the transcoded media. */
  protected DataSource source;
  /** Sink used to "write" out the transcoded media. */
  protected DataSink sink;
  /** Processor used to transcode the media. */
  protected Processor processor;
  /**
   * Model used in constructing the processor, and which specifies track
   * formats and output content type
   */
  protected ProcessorModel model;
  /** State the object is in. */
  protected int state;
  /** Location that the media will be "written" to. */
  protected MediaLocator sinkLocation;
  /** The rate of translation. */
  protected float translationRate;
  /** Process has failed. */
  public static final int FAILED = 0;
  /**
   * Processor is working but not finished. DataSink is yet to start.
   */
  public static final int TRANSLATING = 1;
  /** DataSink has started but not finished. */
  public static final int TRANSFERRING = 3;
  /** Transcoding and transfer is complete. */
  public static final int FINISHED = 4;
  /** String names for each of the states. More user friendly */
  private static final String[] STATE_NAMES = { "Failed", "Translating",
      "<UNUSED>", "Transferring", "Finished" };
  /**
   * Period (in milliseconds) between checks for the blocking transfer method.
   */
  public static final int WAIT_PERIOD = 50;
  /**
   * Wait an "indefinite" period of time for the transfer method to complete.
   * i.e., pass to transfer() if the user wishes to block till the process is
   * complete, regardless of how long it will take.
   */
  public static final int INDEFINITE = Integer.MAX_VALUE;
  /***************************************************************************
   * Construct a transfer/transcode object that transfers media from
   * sourceLocation to destinationLocation, transcoding the tracks as
   * specified by the outputFormats. The output media is to have a content
   * type of outputContainer and the process should (if possible) run at the
   * passed rate.
   **************************************************************************/
  Location2Location(MediaLocator sourceLocation,
      MediaLocator destinationLocation, Format[] outputFormats,
      ContentDescriptor outputContainer, double rate) {
    //////////////////////////////////////////////
    // Construct the processor for the transcoding
    //////////////////////////////////////////////
    state = TRANSLATING;
    sinkLocation = destinationLocation;
    try {
      if (sourceLocation == null)
        model = new ProcessorModel(outputFormats, outputContainer);
      else
        model = new ProcessorModel(sourceLocation, outputFormats,
            outputContainer);
      processor = Manager.createRealizedProcessor(model);
    } catch (Exception e) {
      state = FAILED;
      return;
    }
    translationRate = processor.setRate((float) Math.abs(rate));
    processor.addControllerListener(this);
    ////////////////////////////////////////////////////////////
    // Construct the DataSink and employ an anonymous class as
    // a DataSink listener in order that the end of transfer
    // (completion of task) can be detected.
    ///////////////////////////////////////////////////////////
    source = processor.getDataOutput();
    try {
      sink = Manager.createDataSink(source, sinkLocation);
    } catch (Exception sinkException) {
      state = FAILED;
      processor.removeControllerListener(this);
      processor.close();
      processor = null;
      return;
    }
    sink.addDataSinkListener(new DataSinkListener() {
      public void dataSinkUpdate(DataSinkEvent e) {
        if (e instanceof EndOfStreamEvent) {
          sink.close();
          source.disconnect();
          if (state != FAILED)
            state = FINISHED;
        } else if (e instanceof DataSinkErrorEvent) {
          if (sink != null)
            sink.close();
          if (source != null)
            source.disconnect();
          state = FAILED;
        }
      }
    });
    // Start the transcoding
    processor.start();
  }
  /***************************************************************************
   * Alternate constructor: source and destination specified as Strings, and
   * no rate provided (hence rate of 1.0)
   **************************************************************************/
  Location2Location(String sourceName, String destinationName,
      Format[] outputFormats, ContentDescriptor outputContainer) {
    this(new MediaLocator(sourceName), new MediaLocator(destinationName),
        outputFormats, outputContainer);
  }
  /***************************************************************************
   * Alternate constructor: No rate specified therefore rate of 1.0
   **************************************************************************/
  Location2Location(MediaLocator sourceLocation,
      MediaLocator destinationLocation, Format[] outputFormats,
      ContentDescriptor outputContainer) {
    this(sourceLocation, destinationLocation, outputFormats,
        outputContainer, 1.0f);
  }
  /***************************************************************************
   * Alternate constructor: source and destination specified as Strings.
   **************************************************************************/
  Location2Location(String sourceName, String destinationName,
      Format[] outputFormats, ContentDescriptor outputContainer,
      double rate) {
    this(new MediaLocator(sourceName), new MediaLocator(destinationName),
        outputFormats, outputContainer, rate);
  }
  /***************************************************************************
   * Respond to events from the Processor performing the transcoding. If its
   * task is completed (end of media) close it down. If there is an error
   * close it down and mark the process as FAILED.
   **************************************************************************/
  public synchronized void controllerUpdate(ControllerEvent e) {
    if (state == FAILED)
      return;
    // Transcoding complete.
    if (e instanceof StopEvent) {
      processor.removeControllerListener(this);
      processor.close();
      if (state == TRANSLATING)
        state = TRANSFERRING;
    }
    // Transcoding failed.
    else if (e instanceof ControllerErrorEvent) {
      processor.removeControllerListener(this);
      processor.close();
      state = FAILED;
    }
  }
  /***************************************************************************
   * Initiate the transfer through a DataSink to the destination and wait
   * (block) until the process is complete (or failed) or the supplied number
   * of milliseconds timeout has passed. The method returns the total amount
   * of time it blocked.
   **************************************************************************/
  public int transfer(int timeOut) {
    // Can"t initiate: Processor already failed to transcode
    ////////////////////////////////////////////////////////
    if (state == FAILED)
      return -1;
    // Start the DataSink
    //////////////////////
    try {
      sink.open();
      sink.start();
    } catch (Exception e) {
      state = FAILED;
      return -1;
    }
    if (state == TRANSLATING)
      state = TRANSFERRING;
    if (timeOut <= 0)
      return timeOut;
    // Wait till the process is complete, failed, or the
    // prescribed time has passed.
    /////////////////////////////////////////////////////
    int waited = 0;
    while (state != FAILED && state != FINISHED && waited < timeOut) {
      try {
        Thread.sleep(WAIT_PERIOD);
      } catch (InterruptedException ie) {
      }
      waited += WAIT_PERIOD;
    }
    return waited;
  }
  /***************************************************************************
   * Initiate the transfer through a DataSink to the destination but return
   * immediately to the caller.
   **************************************************************************/
  public void transfer() {
    transfer(-1);
  }
  /***************************************************************************
   * Determine the object"s current state. Returns one of the class constants.
   **************************************************************************/
  public int getState() {
    return state;
  }
  /***************************************************************************
   * Returns the object"s state as a String. A more user friendly version of
   * getState().
   **************************************************************************/
  public String getStateName() {
    return STATE_NAMES[state];
  }
  /***************************************************************************
   * Obtain the rate being used for the process. This is often 1, despite what
   * the user may have supplied as Clocks (hence Processors) don"t have to
   * support any other rate than 1 (and will default to that).
   **************************************************************************/
  public float getRate() {
    return translationRate;
  }
  /***************************************************************************
   * Set the time at which media processing will stop. Specification is in
   * media time. This means only the first "when" amount of the media will be
   * transferred.
   **************************************************************************/
  public void setStopTime(Time when) {
    if (processor != null)
      processor.setStopTime(when);
  }
  /***************************************************************************
   * Stop the processing and hence transfer. This gives user control over the
   * duration of a transfer. It could be started with the transfer() call and
   * after a specified period stop() could be called.
   **************************************************************************/
  public void stop() {
    if (processor != null)
      processor.stop();
  }
}