Camera Display Using JNI

Objective

This document explains how to code a Port-Based Agent with native methods in legacy C code by way of JNI technology.

This is not intended to be a JNI tutorial. If you are not familiar with JNI technology, you can take a look at the JNI Sun Tutorial page.

Table of Contents


Introduction

For our robotics examples we have been using the Pioneer robots. They have a Sony camera and a frame grabber installed. C code is available to control the frame grabber features and for image processing. Since C code can deal with hardware and it is faster than Java code, it does not make sense to rewrite this code in Java. We developed a Java wrapper for the C code using Java Native Interface (JNI) technology.

Camera Display Example

In this example we develop a PBA driver agent (PBD) that samples the video camera and displays it.

C code is available to initialize the frame grabber and sample the video images in different formats. To hide implementation representations from the PBD, we develop a Java class JNIcamera that contains all the native method definitions and calls. This class is instantiated in the PBD and becomes an internal variable of the agent. The C code is compiled as a dynamic library that gets loaded at runtime, when the PBD is instantiated.

Java Details

Here is a section of the JNIcamera source:

public class JNIcamera {

  //Native method declarations
  native int grabSingleFrame();
  native int grabContFrame();
  native int initFrameGrabber();
  native void closeFrameGrabber();
  native int startContCapture();
  native int stopCapture();

  // last display additions to library
  native void getByteFrame(byte[] frame);
  native void getIntFrame(int[] frame);

  public JNIcamera() {
    System.loadLibrary("JNIcamera");
    System.err.println("Loading JNI library for camera-grabber");
  }

  public synchronized int JNIgrabSingleFrame() {
    return grabSingleFrame();
  }

  public synchronized int JNIgrabContFrame() {
    return grabContFrame();
  }
  
  public synchronized int JNIinitFrameGrabber() {
    return initFrameGrabber();
  }

  public synchronized void JNIgetByteFrame(byte[] frame) {
    getByteFrame(frame);
  }
  
  public synchronized void JNIgetIntFrame(int[] frame) {
    getIntFrame(frame);
  }
}

A JNIcamera.so library file has to be created and setup in the library path for this class to load correctly. The library is created using the header file created from JNIcamera.class by java_h, that looks like this:

/*
 * Class:     adaptive_support_vision_JNIcamera
 * Method:    initFrameGrabber
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_adaptive_support_vision_JNIcamera_initFrameGrabber (JNIEnv, jobject);

/*
 * Class:     adaptive_support_vision_JNIcamera
 * Method:    grabSingleFrame
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_adaptive_support_vision_JNIcamera_grabSingleFrame(JNIEnv, jobject);

/*
 * Class:     adaptive_support_vision_JNIcamera
 * Method:    getIntFrame
 * Signature: ([I)V
 */
JNIEXPORT void JNICALL Java_adaptive_support_vision_JNIcamera_getIntFrame
(JNIEnv, jobject, jintArray);

Therefore, the original C code has to be wrapped around these calls to be understandable by the Java Virtual Machine.

Note: The long names are due to the fact that JNIcamera is included in our package adaptive.support.vision.

Finally, the PBD main steps look like this:

package adaptive.agents.drivers;

// Importing JNIcamera
import adaptive.support.vision.*;

// PBA core classes
import adaptive.core.*;

// other util classes ommited

public class PBACameraDisplay extends PBAgent implements Driver {

// some constants
  static final int rows = 120;
  static final int cols = 160;
  static final int resol = 16;
// frame storage variables
  byte[] frame;
  int[]  pixels;
// frame displaying variables
  CamDisplay view;
  Frame Display;
// JNI library clas interface
  static protected JNIcamera Camera;

 /**********************************************************************

   Process our internal state.

   @param 
   
   @return 
      @exception 

  **********************************************************************/
  protected boolean processInternalState(Object state){

  // cut extra stuff here

  // allocating internals
      pixels = new int[rows*cols];
      frame = new byte[frame_size];
      Display = new Frame();
      view = new CamDisplay(rows,cols,resol,pixels); 
      Display.add(view,BorderLayout.CENTER);
      Display.setSize(cols+4,rows+26); 
      Display.show();

      // loading JNI and starting services
      Camera = new JNIcamera();
      // initializing camera-grabber
      if (0>Camera.JNIinitFrameGrabber())
        System.err.println("error: initFrameGrabber");
      if (0>Camera.JNIstartContCapture())
      System.err.println("error: startContCapture");
  }

  /**********************************************************************
  runLoop method required by Runnable Interface.

  @param 
		
  @return 
   
  @exception 

  **********************************************************************/
  
  public void runLoop() {

    // refreshing frame
    Camera.JNIgrabContFrame();
    // tranlating frame to variable
    Camera.JNIgetIntFrame(pixels);
    // refresh display using new pixels
    view.refresh();
    view.repaint();
  }

}






Enrique Ferreira
Last modified: Thu May 18 19:45 EDT 2000