|
Synchronized Auditory and Visual Content
An Introduction with Examples in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Player Classimport java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.media.*;
import javax.swing.*;
/**
* A JPanel that contains a media player
* (using the Java Media Framework)
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class PlayerPanel extends JPanel
implements ControllerListener
{
protected boolean includeVisual, includeControls;
protected Player player;
/**
* Constructor
*
*/
public PlayerPanel(boolean includeVisual,
boolean includeControls)
{
player = null;
this.includeVisual = includeVisual;
this.includeControls = includeControls;
setLayout(new BorderLayout());
}
/**
* Load a media file
*
* @param fn The name of the file
*/
public void loadFile(String fn)
{
Component c;
URL url;
try {
url = new URL("file:"+
System.getProperty("user.dir")+
"/"+
fn);
player = Manager.createPlayer(url);
player.addControllerListener(this);
player.start();
} catch (MalformedURLException mue) {
JOptionPane.showMessageDialog(this,
"Unable to open file!");
} catch (NoPlayerException npe) {
JOptionPane.showMessageDialog(this,
"Unable to create a player!");
} catch (IOException ioe) {
JOptionPane.showMessageDialog(this,
"Unable to connect to source!");
}
}
/**
* Handle controllerUpdate events
* (required by ControllerListener)
*
* @param evt The ControllerEvent
*/
public synchronized void controllerUpdate(ControllerEvent evt)
{
Component c;
if (evt instanceof RealizeCompleteEvent) {
c = player.getVisualComponent();
if ((c != null) && (includeVisual)) {
add(c, BorderLayout.CENTER);
}
c = player.getControlPanelComponent();
if ((c != null) && (includeControls)) {
add(c, BorderLayout.SOUTH);
}
// Force a re-layout
validate();
}
}
}
import java.awt.*;
import javax.swing.*;
/**
* An example that uses a media player
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class PlayerPanelDriver
{
/**
* The entry point of the example
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
boolean includeVisual;
JFrame f;
Container contentPane;
PlayerPanel p;
f = new JFrame();
contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
if (args[0].indexOf(".mpg") >= 0) includeVisual = true;
else includeVisual = false;
p = new PlayerPanel(includeVisual, true);
contentPane.add(p, BorderLayout.CENTER);
f.setSize(320,300);
f.setVisible(true);
p.loadFile(args[0]);
}
}
Processor States in JavaTrackControl objectsProcessor States in Java (cont.)
import java.awt.*;
import javax.swing.*;
/**
* An example that uses a media processor
* to play content
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class ProcessorPanelDriver
{
/**
* The entry point of the example
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
JFrame f;
Container contentPane;
ProcessorPanel p;
f = new JFrame();
contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
p = new ProcessorPanel();
contentPane.add(p, BorderLayout.CENTER);
f.setSize(320,300);
f.setVisible(true);
p.loadAndStart(args[0]);
}
}
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.media.*;
import javax.swing.*;
/**
* A JPanel that contains a media processor
* (using the Java Media Framework)
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class ProcessorPanel extends JPanel
implements ControllerListener
{
protected boolean transitionOK;
protected Object synchronizer;
protected Processor processor;
/**
* Constructor
*
*/
public ProcessorPanel()
{
processor = null;
synchronizer = new Object();
transitionOK = true;
setLayout(new BorderLayout());
}
/**
* Get the Processor associated with this ProcessorPanel
*
* @return The Processor
*/
public Processor getProcessor()
{
return processor;
}
/**
* Configure the Processor
*
* @return true of the Processor was realized
*/
public boolean configure()
{
boolean status;
status = false;
// Put the Processor into the configured state
processor.configure();
if (waitFor(processor.Configured)) {
// Set the content descriptor to null so that the
// processor can be used as a player
processor.setContentDescriptor(null);
status = true;
} else {
JOptionPane.showMessageDialog(this,
"Unable to configure the processor!");
}
return status;
}
/**
* Handle controllerUpdate events
* (required by ControllerListener)
*
* @param evt The ControllerEvent
*/
public synchronized void controllerUpdate(ControllerEvent evt)
{
if ( (evt instanceof ConfigureCompleteEvent) ||
(evt instanceof RealizeCompleteEvent) ||
(evt instanceof PrefetchCompleteEvent) ) {
// Synchronize this block
synchronized(synchronizer) {
transitionOK = true;
synchronizer.notifyAll();
}
} else if (evt instanceof ResourceUnavailableEvent) {
// Synchronize this block
synchronized(synchronizer) {
transitionOK = false;
synchronizer.notifyAll();
}
}
}
/**
* Load and start a media file
*
* @param fn The name of the file
*/
public void loadAndStart(String fn)
{
boolean status;
status = loadFile(fn);
if (status) status = configure();
if (status) status = realize();
}
/**
* Load a media file
*
* @param fn The name of the file
* @return true if the process completed successfully
*/
public boolean loadFile(String fn)
{
boolean status;
URL url;
status = false;
try {
url = new URL("file:"+
System.getProperty("user.dir")+
"/"+fn);
if (url != null) {
processor = Manager.createProcessor(url);
processor.addControllerListener(this);
status = true;
}
} catch (NoProcessorException npe) {
JOptionPane.showMessageDialog(this,
"Unable to create a processor!");
} catch (IOException ioe) {
JOptionPane.showMessageDialog(this,
"Unable to connect to source!");
}
return status;
}
/**
* Realize the Processor
*
*/
public boolean realize()
{
boolean status;
Component c;
status = false;
// Put the Processor into the realized state
processor.prefetch();
if (waitFor(processor.Prefetched)) {
// The Processor has been realized so the
// components can be layed out
c = processor.getVisualComponent();
if (c != null) add(c, BorderLayout.CENTER);
c = processor.getControlPanelComponent();
if (c != null) add(c, BorderLayout.SOUTH);
validate();
// Start the Processor
processor.start();
status = true;
} else {
JOptionPane.showMessageDialog(this,
"Unable to realize the processor!");
}
return status;
}
/**
* Block the thread of execution until the Processor has
* transitioned into the given state.
*
* @param state The state to wait for
* @return false if the transition failed, true otherwise
*/
protected boolean waitFor(int state)
{
// Make this block synchronized
synchronized(synchronizer) {
try {
while ((processor.getState() != state) &&
(transitionOK)) {
synchronizer.wait();
}
} catch (InterruptedException ie) {
// Ignore it
}
}
return transitionOK;
}
}
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.util.*;
import javax.media.*;
import javax.media.renderer.*;
import javax.media.format.*;
/**
* A Canvas that implements the VideoRenderer interface
* and, hence, can be used to display video.
*
* This particular implementation can only be used with RGB
* .mov files
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class RGBRenderer implements VideoRenderer {
protected boolean started;
protected Buffer lastBuffer;
protected Component component;
protected int inputHeight, inputWidth;
protected Format[] supportedFormats;
protected Image destImage;
protected MemoryImageSource sourceImage;
protected Rectangle bounds;
protected RGBFormat inputFormat, supportedRGB;
protected static final int rMask = 0x000000FF;
protected static final int gMask = 0x0000FF00;
protected static final int bMask = 0x00FF0000;
/**
* Constructor
*/
public RGBRenderer()
{
lastBuffer = null;
component = null;
bounds = null;
started = false;
inputWidth = 0;
inputHeight = 0;
// Prepare supported input formats and preferred format
supportedRGB = new RGBFormat(null, // size
Format.NOT_SPECIFIED, // maxDataLength
int[].class, // buffer type
Format.NOT_SPECIFIED, // frame rate
32, // bitsPerPixel
rMask, gMask, bMask, // component masks
1, // pixel stride
Format.NOT_SPECIFIED, // line stride
Format.FALSE, // flipped
Format.NOT_SPECIFIED // endian
);
supportedFormats = new VideoFormat[1];
supportedFormats[0] = supportedRGB;
}
/**
* Close the Renderer (required by VideoRenderer)
*/
public void close()
{
// Do nothing
}
/**
* Get the portion of the Component being used by
* this Renderer (required by VideoRenderer)
*
* @return The Rectangle used (null for the whole Component)
*/
public Rectangle getBounds()
{
return bounds;
}
/**
* Get the Component that this Renderer is
* using (required by VideoRenderer)
*
* @return The Component
*/
public Component getComponent()
{
if (component == null) {
component = new RendererCanvas(this);
}
return component;
}
/**
* Get the Controls for this renderer
* (required by VideoRenderer)
*
* Since this implementation does not support Controls it
* returns an empty array.
*
* @return The controls
*/
public Object[] getControls()
{
return (Object[]) new Control[0];
}
/**
* Get a Control based on a control type
* (required by VideoRenderer)
*
* Since this implementation does not support Controls it
* returns an empty array.
*
* @return The controls
*/
public Object getControl(String controlType)
{
return null;
}
/**
* Get the name of this Renderer
* (required by VideoRenderer)
*
* @return The name
*/
public String getName() {
return "RendererCanvas";
}
/**
* Get the size of the input data
*
* @return The size (in pixels)
*/
public Dimension getSize()
{
return new Dimension(inputWidth, inputHeight);
}
/**
* Get the array of supported formats
* (required by VideoRenderer)
*
* @return The array of supported formats
*/
public Format[] getSupportedInputFormats()
{
return supportedFormats;
}
/**
* Open this Renderer (required by VideoRenderer)
*
*/
public void open() throws ResourceUnavailableException
{
sourceImage = null;
destImage = null;
lastBuffer = null;
}
/**
* Paint the current image
*
* @param g The Graphics context
*/
public void paintImage(Graphics g)
{
Rectangle tempBounds;
if ( (g == null) || (destImage == null) ||
(component == null)) return;
if (bounds == null) {
tempBounds = component.getBounds();
tempBounds.x = 0;
tempBounds.y = 0;
} else {
tempBounds = bounds;
}
g.drawImage(destImage, tempBounds.x, tempBounds.y,
tempBounds.width, tempBounds.height,
0, 0, inputWidth, inputHeight, component);
}
/**
* Process the input data and render it
*
* @param buffer The input data
* @return BUFFER_PROCESSED_OK if successful
*/
public synchronized int process(Buffer buffer)
{
Object data;
Format inf;
Graphics g;
// Initial error checking
if (component == null) return BUFFER_PROCESSED_FAILED;
inf = buffer.getFormat();
if (inf == null) return BUFFER_PROCESSED_FAILED;
if ( (inf != inputFormat) ||
(!buffer.getFormat().equals(inputFormat)) ) {
if (setInputFormat(inf)!=null) {
return BUFFER_PROCESSED_FAILED;
}
}
data = buffer.getData();
if (!(data instanceof int[])) {
return BUFFER_PROCESSED_FAILED;
}
// Check to see if the data have changed
if (lastBuffer != buffer) {
lastBuffer = buffer;
buildImage(buffer);
}
// Render the image
sourceImage.newPixels(0, 0, inputWidth, inputHeight);
g = component.getGraphics();
if (g != null) paintImage(g);
return BUFFER_PROCESSED_OK;
}
/**
* Reset the Renderer (required by VideoRenderer)
*
*/
public void reset()
{
// Do nothing
}
/**
* Set the portion of the Component to use
* (required by VideoRenderer)
*
* @param rect The area to use (null for the whole Component)
*/
public void setBounds(Rectangle bounds)
{
this.bounds = bounds;
}
/**
* Set the Component that the Renderer should
* use (required by VideoRenderer)
*
* @return false if the Renderer can't use the Component
*/
public boolean setComponent(Component comp)
{
component = comp;
return true;
}
/**
* Set the input format (required by VideoRenderer)
*
* @param format The Format of the input data
* @return The Format that was set or null
*/
public Format setInputFormat(Format format)
{
Dimension size;
Format retval;
if ( (format != null) &&
(format instanceof RGBFormat) &&
(format.matches(supportedRGB)) ) {
inputFormat = (RGBFormat)format;
size = inputFormat.getSize();
inputWidth = size.width;
inputHeight = size.height;
retval = format;
} else {
retval = null;
}
return retval;
}
/**
* Start the Renderer (required by VideoRenderer)
*/
public void start()
{
started = true;
}
/**
* Stop the Renderer (required by VideoRenderer)
*/
public void stop()
{
started = false;
}
/**
* Build a new image from the input data
*
* @param buffer The input data
*/
protected void buildImage(Buffer buffer)
{
DirectColorModel colorModel;
Object data;
RGBFormat format;
data = buffer.getData();
if (!(data instanceof int[])) return;
format = (RGBFormat) buffer.getFormat();
colorModel=new DirectColorModel(format.getBitsPerPixel(),
format.getRedMask(),
format.getGreenMask(),
format.getBlueMask());
sourceImage=new MemoryImageSource(format.getLineStride(),
format.getSize().height,
colorModel,
(int[])data, 0,
format.getLineStride());
sourceImage.setAnimated(true);
sourceImage.setFullBufferUpdates(true);
if (component != null) {
destImage = component.createImage(sourceImage);
component.prepareImage(destImage, component);
}
}
}
import java.awt.*;
/**
* A Canvas that is used by an RGBRenderer to display video.
*
* This particular implementation can only be used with an
* RGBRenderer.
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class RendererCanvas extends Canvas
{
RGBRenderer renderer;
/**
* Constructor
*
* @param renderer The RGBRenderer that determines the size
*/
public RendererCanvas(RGBRenderer renderer)
{
this.renderer = renderer;
}
/**
* Get the minimum size of this Canvas
*/
public Dimension getMinimumSize()
{
return renderer.getSize();
}
/**
* Get the preferred size of this Canvas
*/
public Dimension getPreferredSize()
{
return getMinimumSize();
}
/**
* Update this Component
*
* @param g The Graphics context
*/
public void update(Graphics g)
{
// Do nothing
}
/**
* Paint this Component
*
* @param g The Graphics context
*/
public void paint(Graphics g)
{
// This method needs to handle repaints when the
// movie is paused
renderer.paintImage(g);
}
}
import java.awt.*;
import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
import javax.swing.*;
/**
* An example that uses a custom VideoRenderer
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class RendererDriver
{
/**
* The entry point of the example
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
boolean status;
JFrame f;
Container contentPane;
int i;
ProcessorPanel p;
RGBRenderer renderer;
TrackControl videoControl;
TrackControl[] trackControls;
f = new JFrame();
contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
p = new ProcessorPanel();
contentPane.add(p, BorderLayout.CENTER);
status = false;
status = p.loadFile(args[0]);
status = p.configure();
if (status) {
status = false;
// Get the video track control (if there is one)
trackControls = p.getProcessor().getTrackControls();
videoControl = null;
for (i=0; i < trackControls.length; i++) {
if (trackControls[i].getFormat()
instanceof VideoFormat) {
videoControl = trackControls[i];
break;
}
}
if (videoControl != null) {
// Set the Renderer for the video track control
try {
renderer = new RGBRenderer();
videoControl.setRenderer(renderer);
status = true;
} catch (UnsupportedPlugInException upie) {
System.out.println("Unsupported PlugIn");
}
}
}
if (status) {
p.realize();
}
f.setSize(320,300);
f.setVisible(true);
}
}
import java.awt.*;
import javax.media.*;
/**
* An RGBRenderer that "pops-up" text
*
* This particular implementation can only be used with RGB
* .mov files
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*/
public class PopUpRenderer extends RGBRenderer
{
protected int index, frame;
protected int[] duration, frames;
protected String[] text;
/**
* Constructor
*
* @param frames Array of frame numbers for popups
* @param text Array of text for popups
* @param duration Array of durations (in frames) for popups
*/
public PopUpRenderer(int[] frames,
String[] text,
int[] duration)
{
this.frames = frames;
this.text = text;
this.duration = duration;
frame = -1;
index = 0;
}
/**
* Paint the current image
*
* @param g The Graphics context
*/
public void paintImage(Graphics g)
{
// This should be buffered to avoid flicker
super.paintImage(g);
if (index < frames.length) {
if ((frame >= frames[index]) &&
(frame <= frames[index]+duration[index])) {
g.setColor(Color.white);
g.fillRect(50,50,150,25);
g.setColor(Color.black);
g.drawString(text[index], 70, 70);
if (frame ==
frames[index]+duration[index]) index++;
}
}
}
/**
* Process the input data and render it
*
* @param buffer The input data
* @return BUFFER_PROCESSED_OK if successful
*/
public synchronized int process(Buffer buffer)
{
frame++;
return super.process(buffer);
}
}
import java.awt.*;
import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
import javax.swing.*;
/**
* An example that uses a custom VideoRenderer that
* includes "pop-up" text
*
* @version 1.0
* @author Prof. David Bernstein, James Madison University
*
*/
public class PopUpRendererDriver
{
/**
* The entry point of the example
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
boolean status;
JFrame f;
Container contentPane;
int i;
int[] frames, duration;
ProcessorPanel p;
PopUpRenderer renderer;
String[] text;
TrackControl videoControl;
TrackControl[] trackControls;
text = new String[2];
text[0] = "Nice Mask!";
text[1] = "Did he say organisms?";
frames = new int[2];
frames[0] = 70;
frames[1] = 135;
duration = new int[2];
duration[0] = 10;
duration[1] = 20;
f = new JFrame();
contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
p = new ProcessorPanel();
contentPane.add(p, BorderLayout.CENTER);
status = false;
status = p.loadFile(args[0]);
status = p.configure();
if (status) {
status = false;
// Get the video track control (if there is one)
trackControls = p.getProcessor().getTrackControls();
videoControl = null;
for (i=0; i < trackControls.length; i++) {
if (trackControls[i].getFormat()
instanceof VideoFormat) {
videoControl = trackControls[i];
break;
}
}
if (videoControl != null) {
// Set the Renderer for the video track control
try {
renderer =
new PopUpRenderer(frames, text, duration);
videoControl.setRenderer(renderer);
status = true;
} catch (UnsupportedPlugInException upie) {
System.out.println("Unsupported PlugIn");
}
}
}
if (status) {
p.realize();
}
f.setSize(320,300);
f.setVisible(true);
}
}