package net.sf.fmj.media.renderer.video;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.media.Buffer;
import javax.media.Format;
import javax.media.ResourceUnavailableException;
import javax.media.format.RGBFormat;
import javax.media.renderer.VideoRenderer;
/**
* A VideoRenderer that handles packed integer RGB formats.
*
* It uses Java2D to render incoming RGB images.
*
* TODO: support byte-array based images. See ImageToBuffer.
*
* @author Warren Bloomer
*
*/
public class Java2dRenderer implements VideoRenderer {
private String name = "Java2D Video Renderer";
/** supported input formats */
private Format[] supportedFormats;
/** the actual input format */
private RGBFormat inputFormat;
/** the visual component to render video into */
private JVideoComponent component;
/** bounds for the input frame */
private Rectangle bounds = new Rectangle(0, 0, 10, 10);
/** an offscreen image to write to */
private BufferedImage bufferedImage;
/**
* Constructor
*/
public Java2dRenderer() {
int rMask = 0x00FF0000;
int gMask = 0x0000FF00;
int bMask = 0x000000FF;
supportedFormats = new Format[] {
// RGB format
new RGBFormat(
null, // size
Format.NOT_SPECIFIED, // maxDataLength
Format.intArray, // 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
),
// BGR format
new RGBFormat(
null, // size
Format.NOT_SPECIFIED, // maxDataLength
Format.intArray, // buffer type
Format.NOT_SPECIFIED, // frame rate
32, // bitsPerPixel
bMask, gMask, rMask, // component masks
1, // pixel stride
Format.NOT_SPECIFIED, // line stride
Format.FALSE, // flipped
Format.NOT_SPECIFIED // endian
)
};
}
/*------------------- PlugIn interface ------------------- */
/**
* Return the name of the plugin
*/
public String getName() {
return name;
}
/**
* Opens the plugin
*/
public void open() throws ResourceUnavailableException {
createImage();
}
/**
* Resets the state of the plug-in. Typically at end of media or when media
* is repositioned.
*/
public void reset() {
// Nothing to do
}
/**
* Close the plugin.
*/
public synchronized void close() {
bufferedImage = null;
}
/*------------------------- Controls interface ------------------------ */
/**
* Returns an array of supported controls
**/
public Object[] getControls() {
return new Object[] {};
}
/**
* Return the control based on a control type for the PlugIn.
*/
public Object getControl(String controlType) {
return null;
}
/* ----------------------- Renderer interface -------------------------- */
/**
* Start the renderer.
*/
public void start() {
// nothing to do
}
/**
* Stop the renderer.
*/
public void stop() {
// nothing to do
}
/**
* Lists the possible input formats supported by this plug-in.
*/
public Format[] getSupportedInputFormats() {
return supportedFormats;
}
/**
* Set the data input format.
*/
public Format setInputFormat(Format format) {
for (int i=0; i<supportedFormats.length; i++) {
if (format.matches(supportedFormats[i])) {
this.inputFormat = (RGBFormat) format;
Dimension size = inputFormat.getSize();
if (size != null) {
this.bounds.setSize(size);
}
getComponent().setPreferredSize(size);
return format;
}
}
return null;
}
/**
* Processes the data and renders it to a component
*/
public int process(Buffer buffer) {
if (component == null) {
return BUFFER_PROCESSED_FAILED;
}
Format inFormat = buffer.getFormat();
if (inFormat == null) {
return BUFFER_PROCESSED_FAILED;
}
if (inFormat != inputFormat || !inFormat.equals(inputFormat)) {
// format has changed
if (setInputFormat(inFormat) == null) {
return BUFFER_PROCESSED_FAILED;
}
// recreate bufferedImage
createImage();
}
Object data = buffer.getData();
if (data == null) {
return BUFFER_PROCESSED_FAILED;
}
if ( inFormat.getDataType() != Format.intArray ) {
// wrong data type
return BUFFER_PROCESSED_FAILED;
}
Dimension size = inputFormat.getSize();
synchronized (component) {
// write data to buffered image
bufferedImage.getRaster().setDataElements(0, 0, size.width, size.height, data);
// repaint the component
component.setImage(bufferedImage);
}
return BUFFER_PROCESSED_OK;
}
/* ---------------------- VideoRenderer interface ---------------------- */
/**
* Try to set the component to render to.
*/
public boolean setComponent(Component comp) {
return false;
}
/**
* Get the visual component.
*/
public Component getComponent() {
if (component == null) {
component = new JVideoComponent();
}
return component;
}
/**
* Get the bounds of the component.
*/
public Rectangle getBounds() {
return bounds;
}
/**
* Set the bounds of the visual component.
*/
public void setBounds(Rectangle rect) {
this.bounds.setBounds(rect);
}
/* -------------------- private utilities ----------------------- */
/**
* Create the buffered image to write raster data to.
*/
private void createImage() {
if (inputFormat == null) {
// can not create image
return;
}
Dimension size = inputFormat.getSize();
if (size == null) {
// can not create image
return;
}
// look at RGB masks to determine image type.
int imageType;
if (inputFormat.getRedMask() == 0x000000FF) {
imageType = BufferedImage.TYPE_INT_BGR;
}
else {
imageType = BufferedImage.TYPE_INT_RGB;
}
bufferedImage = new BufferedImage(size.width, size.height, imageType);
}
}