Package net.sf.fmj.media.renderer.video

Source Code of net.sf.fmj.media.renderer.video.GlRenderer

/*
*
*/
package net.sf.fmj.media.renderer.video;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.logging.Logger;

import javax.media.Buffer;
import javax.media.Control;
import javax.media.Format;
import javax.media.ResourceUnavailableException;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;
import javax.media.renderer.VideoRenderer;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;

/**
* A VideoRenderer that uses the JOGL OpenGL library.
*
* @author Warren Bloomer
*/
public class GlRenderer implements VideoRenderer {

  private static final Logger logger = Logger.getAnonymousLogger();

  /** The descriptive name of this renderer */
  private static final String name = "GL Renderer";

  /** the GL component to render video data onto */
  private GLCanvas canvas;
  //private GLJPanel canvas;

  /** an optional component that may contain the GL component */
  private Component component = null;

  /** an array of supported input video formats */
  private Format[] supportedFormats;

  /** the format of the video input */
  private RGBFormat inputFormat;

  /** a Buffer for a frame of video data. */
  private java.nio.Buffer frameData;

  /** the underlying video data array */
  private Object frameArray;

  private int inWidth = 0;

  private int inHeight = 0;
 
  private Rectangle reqBounds = null;

  private boolean flip = false;

  private float zoomX = 1f;
 
  private float zoomY = 1f;

  /** an object used for synchronizing access to the video data buffer */
  private Object syncObject = new Object();

  /**
   * Constructor
   */
  public GlRenderer() {
    //logger.info("GlRenderer constructing...");
    GLCapabilities glCaps = new GLCapabilities();
    glCaps.setDoubleBuffered(true);
    glCaps.setHardwareAccelerated(true);

    canvas = new GLCanvas(glCaps);
    //canvas = new GLJPanel(glCaps);
   
    //canvas.setAutoSwapBufferMode(true);

    canvas.addGLEventListener(new GLEventListener() {
      public void display(GLAutoDrawable drawable) {
        synchronized (syncObject) {
          draw(drawable.getGL());
        }
      }

      public void displayChanged(GLAutoDrawable drawable, boolean arg1, boolean arg2) {
      }

      public void init(GLAutoDrawable drawable) {
        drawable.getGL().setSwapInterval(1);
      }

      public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4) {
        synchronized (syncObject) {
          updateScale();
          draw(drawable.getGL());
        }
      }
    });

    // Prepare supported input formats and preferred format

    int rMask = 0x00FF0000;
    int gMask = 0x0000FF00;
    int bMask = 0x000000FF;

    supportedFormats = new VideoFormat[] {
        // 24bit BGR format
        new RGBFormat(null,
            Format.NOT_SPECIFIED,
            Format.byteArray,
            Format.NOT_SPECIFIED,
            24,
            3, 2, 1,
            3,
            Format.NOT_SPECIFIED,
            Format.TRUE,
            Format.NOT_SPECIFIED
        ),

        // 32bit 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
        ),

        // 32 bit 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
        )
    };

    // determine whether to flip the image
    String os = System.getProperty("os.name");
    if (os.startsWith("Win") || os.startsWith("win")) {
      flip = true;
    }
    else {
      flip = false;
    }

  }

  /* ---------------------- Controls interface --------------------------- */

  /**
   * Returns an array of supported controls
   **/
  public Object[] getControls() {
    // No controls
    return (Object[]) new Control[0];
  }

  /**
   * Return the control based on a control type for the PlugIn.
   */
  public Object getControl(String controlType) {
    try {
      Class cls = Class.forName(controlType);
      Object controls[] = getControls();
      for (int i = 0; i < controls.length; i++) {
        if (cls.isInstance(controls[i])) {
          return controls[i];
        }
      }
      return null;
    }
    catch (Exception e) { // no such controlType or such control
      return null;
    }
  }

  /* ---------------------- PlugIn implementation ------------------------- */

  public String getName() {
    return name;
  }

  /**
   * Opens the plugin
   */
  public void open() throws ResourceUnavailableException {
    //logger.info("Opening...");
  }

  /**
   * Resets the state of the plug-in. Typically at end of media or when media
   * is repositioned.
   */
  public void reset() {
    // Nothing to do
    //logger.info("Resetting...");
  }

  public synchronized void close() {
    //logger.info("Closing...");
  }

  /* ---------------------- Renderer implementation ------------------------------ */

  public void start() {
    //logger.info("Starting...");
    //started = true;
  }

  public void stop() {
    //logger.info("Stopping...");
    //started = false;
  }

  /**
   * 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) {
    //logger.info("Setting input format: " + format);

    if (format != null && format instanceof RGBFormat) {
      for (int i = 0; i < supportedFormats.length; i++) {
        if (format.matches(supportedFormats[i])) {

          this.inputFormat = (RGBFormat) format;
          Dimension size = inputFormat.getSize();

          if (size != null) {
            inWidth = size.width;
            inHeight = size.height;
            updateScale();
          }
          return format;
        }
      }
    }
    else {
      // TODO handle YUV and use 3D texture map for conversion
    }

    //logger.info("Unsupported format: " + format);
    return null;
  }

  /**
   * Processes the data and renders it to a component
   */
  public int process(Buffer buffer) {
    //logger.info("process...");

    if (buffer == null || buffer.getLength() <= 0) {
      //logger.info("zero length buffer");
      return BUFFER_PROCESSED_OK;
    }

    Format format = buffer.getFormat();
    if (format instanceof VideoFormat) {
      Dimension size = ((VideoFormat) format).getSize();
      if ((size != null) && (size.width != inWidth || size.height != inHeight)) {
        inWidth = size.width;
        inHeight = size.height;
        updateScale();
      }
    }

    synchronized (syncObject) {
      Object data = buffer.getData();
      if (data == null) {
        return BUFFER_PROCESSED_FAILED;
      }

      frameArray = buffer.getData();
      if (format.getDataType() == Format.byteArray) {
        frameData = ByteBuffer.wrap((byte[]) frameArray);
      }
      else if (format.getDataType() == Format.intArray) {
        frameData = IntBuffer.wrap((int[]) frameArray);
      }
      else {
        return BUFFER_PROCESSED_FAILED;
      }

      /*
      if (format.getDataType() == Format.byteArray) {
        if (frameArray == null || ((byte[])frameArray).length < buffer.getLength() ) {
          frameArray = new byte[buffer.getLength()];
          frameData = ByteBuffer.wrap((byte[]) frameArray);
        }
      }
      else if (format.getDataType() == Format.intArray) {
        if (frameArray == null || ((int[])frameArray).length < buffer.getLength() ) {
          frameArray = new int[buffer.getLength()];
          frameData = IntBuffer.wrap((int[]) frameArray);
        }
      }
      else {
        return BUFFER_PROCESSED_FAILED;
      }

      // copy buffer data to the array that is wrapped in a nio.Buffer
      System.arraycopy(data, 0, frameArray, 0, buffer.getLength());
      */
    }

    // repaint the canvas
    canvas.repaint();

    return BUFFER_PROCESSED_OK;
  }

  /* ---------------------- VideoRenderer implementation ----------------------------- */

  /**
   * 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() {
    //logger.info("Getting component.  component=" + component + ". canvas=" + canvas);
    if (component != null) {
      return component;
    }
    else {
      return canvas;
    }
  }

  /**
   * Requests the renderer to draw into a specified AWT component.
   * Returns false if the renderer cannot draw into the specified
   * component.
   */
  public boolean setComponent(java.awt.Component comp) {
    //logger.info("Setting component: " + comp);

    if (comp instanceof Container) {
      ((Container) comp).setLayout(new BorderLayout());
      ((Container) comp).add(canvas, BorderLayout.CENTER);
      this.component = comp;
      return true;
    }
    else {
      this.component = null;
      return false;
    }
  }

  /**
   * 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(java.awt.Rectangle rect) {
    reqBounds = rect;
  }

  /**
   * Returns the region in the component where the video will be
   * rendered to. Returns null if the entire component is being used.
   */
  public java.awt.Rectangle getBounds() {
    return reqBounds;
  }

  /* --------------------- private methods ---------------------- */

  /**
   * Draw the scene.
   */
  private void draw(GL gl) {
    if (inputFormat != null) {
      gl.glMatrixMode(GL.GL_MODELVIEW);
      gl.glPushMatrix();
      gl.glLoadIdentity();

      gl.glMatrixMode(GL.GL_PROJECTION);
      gl.glPushMatrix();
      gl.glLoadIdentity();

      // draw the image - may use display list
      drawImage(gl);

      // pop perspective
      gl.glPopMatrix();
      gl.glMatrixMode(GL.GL_MODELVIEW);
      gl.glPopMatrix();

    }
  }

  private void drawImage(GL gl) {
    //logger.info("drawing video image");

    if (frameData == null) {
      return;
    }

    int rgbFormat = GL.GL_RGB;
    int dataType = GL.GL_UNSIGNED_BYTE;
   
    if (inputFormat.getDataType() == Format.byteArray) {
      dataType = GL.GL_UNSIGNED_BYTE;
    }
    else if (inputFormat.getDataType() == Format.intArray) {
      dataType = GL.GL_UNSIGNED_INT_8_8_8_8_REV;
    }
   
    switch (inputFormat.getBitsPerPixel()) {
      case 24:
        if (inputFormat.getRedMask() > 1) {
          rgbFormat = GL.GL_BGR;
        }
        else {
          rgbFormat = GL.GL_RGB;
        }
        break;
       
      case 32:
        if (inputFormat.getRedMask() > 0xFF) {
          rgbFormat = GL.GL_BGRA;
        }
        else {
          rgbFormat = GL.GL_RGBA;
        }
        break;
    }

    gl.glPixelZoom(zoomX, zoomY);
    gl.glRasterPos2i(-1, 1);
    gl.glDrawPixels(inWidth, inHeight, rgbFormat, dataType, frameData);
  }
 
  private void updateScale() {
    if (inputFormat != null) {
      //logger.info("Updating scale...");

      Dimension preferredSize = new Dimension(inWidth, inHeight);
      canvas.setPreferredSize(preferredSize);

      zoomX = (float)canvas.getWidth()/(float)inWidth;
      zoomY = -(float)canvas.getHeight()/(float)inHeight;
    }
  }
}
TOP

Related Classes of net.sf.fmj.media.renderer.video.GlRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.