/*
* @(#)BasicVideoRenderer.java 1.22 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.media.renderer.video;
import javax.media.*;
import javax.media.control.FrameGrabbingControl;
import javax.media.renderer.VideoRenderer;
import javax.media.Format;
import javax.media.format.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.util.Vector;
import com.sun.media.*;
/**
* A base implementation for a VideoRenderer
* @since JMF 2.0
*/
public abstract class BasicVideoRenderer extends BasicPlugIn
implements VideoRenderer, FrameGrabbingControl {
/*************************************************************************
* Variables and Constants
*************************************************************************/
// The descriptive name of this renderer
protected String name;
protected transient VideoFormat [] supportedFormats = null;
protected VideoFormat inputFormat = null;
protected int outWidth = -1;
protected int outHeight = -1;
protected int inWidth = -1;
protected int inHeight = -1;
protected Component component = null;
protected ComponentListener compListener = null;
protected boolean componentAvailable = false;
protected Rectangle bounds = null;
protected boolean started = false;
protected Control [] controls = null;
protected FrameGrabbingControl frameGrabber = null;
protected ExtBuffer lastBuffer = new ExtBuffer();
protected Object lastData = null, lastHdr = null;
/*************************************************************************
* Constructor
*************************************************************************/
public BasicVideoRenderer(String name) {
this.name = name;
}
/*************************************************************************
* PlugIn methods
*************************************************************************/
/**
* Returns a descriptive name for the plug-in.
* This is a user readable string.
*/
public String getName() {
return name;
}
/**
* Lists the possible input formats supported by this plug-in.
*/
public Format [] getSupportedInputFormats() {
return supportedFormats;
}
/**
* Opens the plug-in software or hardware component and acquires
* necessary resources. If all the needed resources could not be
* acquired, it throws a ResourceUnavailableException. Data should not
* be passed into the plug-in without first calling this method.
*/
public void open() throws ResourceUnavailableException {
// sub class can override
}
/**
* Closes the plug-in component and releases resources. No more data
* will be accepted by the plug-in after a call to this method. The
* plug-in can be reinstated after being closed by calling
* <code>open</code>.
*/
public void close() {
// sub class can override
}
/**
* Resets the state of the plug-in. Typically at end of media or when media
* is repositioned.
*/
public void reset() {
// sub class can override
}
public int process(Buffer inbuffer) {
if (inbuffer.getLength() == 0)
return BUFFER_PROCESSED_OK;
int result;
//System.err.println("BasicVideoRenderer.process() not implemented");
synchronized (lastBuffer) {
result = doProcess(inbuffer);
// Keep the last buffer
if ( result == BUFFER_PROCESSED_OK ) {
lastBuffer.copy(inbuffer, true);
}
}
return result;
}
protected abstract int doProcess(Buffer buffer);
/*************************************************************************
* Renderer methods
*************************************************************************/
/**
* Set the data input format.
* @return null if the format is not supported.
*/
public Format setInputFormat(Format format) {
if (matches(format, supportedFormats) != null) {
inputFormat = (VideoFormat) format;
Dimension size = inputFormat.getSize();
if (size != null) {
inWidth = size.width;
inHeight = size.height;
}
return format;
} else
return null;
}
public void start() {
started = true;
}
public void stop() {
started = false;
}
/*************************************************************************
* VideoRenderer methods
*************************************************************************/
/**
* Returns an AWT component that it will render to. Returns null
* if it is not rendering to an AWT component.
*/
public java.awt.Component getComponent() {
if (component == null) {
// TODO: Try MSHeavyComponent for MS VM
try {
Class mshc = Class.forName("com.sun.media.renderer.video.MSHeavyComponent");
if (mshc != null)
component = (Component) mshc.newInstance();
} catch (Throwable t) {
component = new HeavyComponent();
}
((HeavyComponent)component).setRenderer( this );
component.setBackground(getPreferredBackground());
if (compListener == null)
compListener = new CompListener();
component.addComponentListener(compListener);
}
return component;
}
/**
* Requests the renderer to draw into a specified AWT component.
* Returns false if the renderer cannot draw into the specified
* component.
*/
public synchronized boolean setComponent(java.awt.Component comp) {
reset();
component = comp;
if (compListener == null)
compListener = new CompListener();
component.addComponentListener(compListener);
return true;
}
/**
* Sets the region in the component where the video is to be
* rendered to. Video is to be scaled if necessary. If <code>rect</code>
* is null, then the video occupies the entire component.
*/
public void setBounds(Rectangle rect) {
bounds = rect;
}
/**
* Returns the region in the component where the video will be
* rendered to. Returns null if the entire component is being used.
*/
public Rectangle getBounds() {
return bounds;
}
/*************************************************************************
* Local methods
*************************************************************************/
protected Color getPreferredBackground() {
return Color.black;
}
void resized(Component c) {
if (c != null && c == component) {
Dimension d = component.getSize();
outWidth = d.width;
outHeight = d.height;
//repaint();
}
}
protected synchronized void setAvailable(boolean on) {
componentAvailable = on;
if (!componentAvailable)
removingComponent();
}
protected void removingComponent() {
}
protected Dimension myPreferredSize() {
return new Dimension(inWidth, inHeight);
}
protected boolean isStarted() {
return started;
}
protected void repaint() {
System.err.println("repaint call not implemented on this renderer");
}
/*************************************************************************
* Controls methods
*************************************************************************/
public Object [] getControls() {
if (controls != null)
return controls;
frameGrabber = (FrameGrabbingControl) this;
controls = new Control[1];
controls[0] = frameGrabber;
return controls;
}
public Component getControlComponent() {
return null;
}
public Buffer grabFrame() {
synchronized (lastBuffer) {
Buffer newBuffer = new Buffer();
newBuffer.setFormat(lastBuffer.getFormat());
newBuffer.setFlags(lastBuffer.getFlags());
newBuffer.setLength(lastBuffer.getLength());
newBuffer.setOffset(0);
newBuffer.setHeader(lastBuffer.getHeader());
newBuffer.setData(lastBuffer.getData());
Object data = lastBuffer.getData();
int length = lastBuffer.getLength();
Object newData;
if (data instanceof byte[])
newData = new byte[length];
else if (data instanceof short[])
newData = new short[length];
else if (data instanceof int[])
newData = new int[length];
else
return newBuffer;
System.arraycopy(data, lastBuffer.getOffset(),
newData, 0,
length);
newBuffer.setData(newData);
return newBuffer;
}
}
/*************************************************************************
* INNER CLASSES
*************************************************************************/
public class CompListener extends ComponentAdapter {
public void componentResized(ComponentEvent ce) {
resized(ce.getComponent());
}
}
}
|