Java/2D Graphics GUI/Media
Содержание
- 1 A Bare Bones Player: play the media object
- 2 Capture audio or video through devices connected to the PC
- 3 Choose the media they wish to play
- 4 Do Audio Capture
- 5 Java Media: Find Components
- 6 List all capture devices currently known to the JMF
- 7 Play the media object
- 8 Play the media object 3
- 9 Query the manager class about the configuration and support of JMF
- 10 Show the Location2Location class in action
- 11 Statistics about the tracks that compose a media object
- 12 Transfer media from one location to another carrying out the specified
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();
}
}