/* * @(#)AWTRenderer.java 1.25 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.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.*; import com.sun.media.util.Arch; /** * Renderer for RGB images using AWT Image. * @since JMF 2.0 */ public class AWTRenderer extends BasicVideoRenderer implements Blitter { /************************************************************************* * Variables and Constants *************************************************************************/ // The descriptive name of this renderer private static final String MyName = "AWT Renderer"; private transient Vector cacheInputData = null; private transient Vector cacheInputImage = null; private transient Vector cacheOutputImage = null; private transient Image lastImage = null; private RGBFormat supportedRGB = null; private RGBFormat supportedOther = null; private transient int lastWidth = 1; private transient int lastHeight = 1; private Blitter blitter = null; static public String vendor = null; static public boolean runningOnMac = false; static { try { vendor = System.getProperty("java.vendor"); if (vendor != null) { vendor = vendor.toUpperCase(); if (vendor.startsWith("APPLE")) { runningOnMac = true; } } } catch (Throwable e) { // Non-fatal error. No need to do anything. } } /************************************************************************* * Constructor *************************************************************************/ public AWTRenderer() { this(MyName); } public AWTRenderer(String name) { super(name); // Prepare supported input formats and preferred format int rMask, gMask, bMask; if ((Arch.getArch() & Arch.SOLARIS) != 0 && !runningOnMac) { rMask = 0x000000FF; gMask = 0x0000FF00; bMask = 0x00FF0000; } else { bMask = 0x000000FF; gMask = 0x0000FF00; rMask = 0x00FF0000; } supportedRGB = new RGBFormat(null, Format.NOT_SPECIFIED, Format.intArray, Format.NOT_SPECIFIED, // frame rate 32, rMask, gMask, bMask, 1, Format.NOT_SPECIFIED, Format.FALSE, // flipped Format.NOT_SPECIFIED // endian ); supportedOther = new RGBFormat(null, Format.NOT_SPECIFIED, Format.intArray, Format.NOT_SPECIFIED, // frame rate 32, bMask, gMask, rMask, 1, Format.NOT_SPECIFIED, Format.FALSE, // flipped Format.NOT_SPECIFIED // endian ); supportedFormats = new VideoFormat[2]; supportedFormats[0] = supportedRGB; supportedFormats[1] = supportedOther; // Setting ColorModel does not really work on the Mac. // So there's only one format supported by the Mac. if (runningOnMac) supportedFormats[1] = supportedRGB; try { Class cls = Class.forName("com.sun.media.renderer.video.Java2DRenderer"); blitter = (Blitter) cls.newInstance(); //blitter.setRenderer(this); } catch (Throwable t) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; blitter = this; } } public boolean isLightWeight() { return false; } /************************************************************************* * PlugIn methods *************************************************************************/ /** * 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 { cacheInputData = new Vector(); cacheInputImage = new Vector(); cacheOutputImage = new Vector(); } /** * Resets the state of the plug-in. Typically at end of media or when media * is repositioned. */ public synchronized void reset() { cacheInputData = new Vector(); cacheInputImage = new Vector(); cacheOutputImage = new Vector(); } /************************************************************************* * Renderer methods *************************************************************************/ /** * Set the data input format. * @return false if the format is not supported. */ public Format setInputFormat(Format format) { if (super.setInputFormat(format) != null) { reset(); return format; } else return null; } /** * Processes the data and renders it to the output device * represented by this renderer. */ protected synchronized int doProcess(Buffer buffer) { if (component == null) return BUFFER_PROCESSED_OK; if (!buffer.getFormat().equals(inputFormat)) { Format in = buffer.getFormat(); if (matches(in, supportedFormats) == null) return BUFFER_PROCESSED_FAILED; else { inputFormat = (RGBFormat) in; } } Object data = buffer.getData(); if (!(data instanceof int[])) return BUFFER_PROCESSED_FAILED; int cacheSize = cacheInputData.size(); int i; boolean found = false; for (i = 0; i < cacheSize; ++i) { Object bufKnown = cacheInputData.elementAt(i); if (bufKnown == data) { found = true; break; } } // Data not cached? Add to the cache and create a new Image wrapper. if (!found) i = blitter.newData(buffer, cacheInputImage, cacheOutputImage, cacheInputData); // Couldn't create Image if (i < 0) return BUFFER_PROCESSED_FAILED; RGBFormat format = (RGBFormat)buffer.getFormat(); Dimension size = format.getSize(); inWidth = size.width; inHeight = size.height; if (outWidth == -1) outWidth = size.width; if (outHeight == -1) outHeight = size.height; lastImage = blitter.process(buffer, cacheInputImage.elementAt(i), cacheOutputImage.elementAt(i), size); lastWidth = size.width; lastHeight = size.height; if (!isLightWeight()) { Graphics g = component.getGraphics(); if (g != null) { blitter.draw(g, component, lastImage, 0, 0, outWidth, outHeight, 0, 0, size.width, size.height); } } else { component.repaint(); } return BUFFER_PROCESSED_OK; } protected void repaint() { if (!isStarted() && lastImage != null) { Graphics g = component.getGraphics(); blitter.draw(g, component, lastImage, 0, 0, outWidth, outHeight, 0, 0, lastWidth, lastHeight); } } /** * 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) { if (isLightWeight()) { component = new LightComponent(); component.setBackground(getPreferredBackground()); if (compListener == null) compListener = new CompListener(); component.addComponentListener(compListener); } else component = super.getComponent(); } return component; } public synchronized void resized(Component c) { super.resized(c); if (blitter != this) blitter.resized(c); } /**************************************************************** * Blitter methods ****************************************************************/ public Image process(Buffer buffer, Object cacheInputImage, Object cacheOutputImage, Dimension size) { MemoryImageSource sourceImage = (MemoryImageSource)cacheInputImage; Image lastImage = (Image) cacheOutputImage; sourceImage.newPixels(0, 0, size.width, size.height); return lastImage; } public void draw(Graphics g, Component component, Image lastImage, int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh) { if (g != null) g.drawImage(lastImage, dx, dy, dw, dh, sx, sy, sw, sh, component); } public void paint(Graphics g) { if (g != null && lastImage != null) blitter.draw(g, component, lastImage, 0, 0, outWidth, outHeight, 0, 0, lastWidth, lastHeight); } public int newData(Buffer buffer, Vector cacheInputImage, Vector cacheOutputImage, Vector cacheInputData) { Object data = buffer.getData(); if (!(data instanceof int[])) return -1; RGBFormat format = (RGBFormat) buffer.getFormat(); DirectColorModel dcm = new DirectColorModel(format.getBitsPerPixel(), format.getRedMask(), format.getGreenMask(), format.getBlueMask()); MemoryImageSource sourceImage = new MemoryImageSource(format.getLineStride(), format.getSize().height, dcm, (int[])data, 0, format.getLineStride()); sourceImage.setAnimated(true); sourceImage.setFullBufferUpdates(true); Image destImage = null; if (component != null) { destImage = component.createImage(sourceImage); component.prepareImage(destImage, component); } cacheOutputImage.addElement(destImage); cacheInputData.addElement(data); cacheInputImage.addElement(sourceImage); return cacheInputImage.size() - 1; } public class LightComponent extends Component { public synchronized void paint(Graphics g) { AWTRenderer.this.paint(g); } public synchronized void update(Graphics g) { } public Dimension getMinimumSize() { return new Dimension(1, 1); } public Dimension getPreferredSize() { return myPreferredSize(); } public synchronized void addNotify() { super.addNotify(); setAvailable(true); } public synchronized void removeNotify() { setAvailable(false); super.removeNotify(); } } }