Intelligent Video Conferencing
Java & C Source Code for Video Conferencing
Subsystem
*** IntScrollbar.java
// IntScrollbar
import java.awt.*;
import java.util.*;
public class IntScrollbar extends Scrollbar implements Observer
{
private ObservableInt intValue;
// IntScrollbar -- constructor for a java.awt.Scrollbar
// which observes the intValue
public IntScrollbar(ObservableInt newValue)
{
super();
intValue = newValue;
intValue.addObserver(this);
setValue(intValue.getValue());
}
// IntScrollbar -- constructor for a java.awt.Scrollbar
// which supports different orientations of the
// scrollbar, as does java.awt.Scrollbar
public IntScrollbar(ObservableInt newValue, int orientation)
{
super(orientation);
intValue = newValue;
intValue.addObserver(this);
setValue(intValue.getValue());
}
// Int Scollbar -- another constructor, allowing for a more
// flexible java.lang.Scrollbar
public IntScrollbar(ObservableInt newValue, int orientation,
int value, int pageSize, int lowValue, int highValue)
{
super(orientation, value, pageSize, lowValue, highValue);
intValue = newValue;
intValue.addObserver(this);
setValue(intValue.getValue());
}
// handler for the IntScrollbar object; passes event to
// super class if event is supported by that class.
// if not, update value of intValue to current value
// of scrollbar
public boolean handleEvent(Event evt)
{
if (super.handleEvent(evt))
{
return true;
}
intValue.setValue(getValue());
return true;
}
// update method -- updates scrollbar's value when
// the observed intValue changes
public void update(Observable obs, Object arg)
{
setValue(intValue.getValue());
}
}
*** IntTextField.java
// IntTextField
import java.awt.*;
import java.util.*;
public class IntTextField extends TextField implements Observer
{
private ObservableInt intValue;
// constructor for a text field which follows an
// integer
public IntTextField(ObservableInt theInt)
{
super(""+theInt.getValue(), 3);
intValue = theInt;
intValue.addObserver(this);
}
// action handler updates value of the observed when
// this IntTextField is changed. The empty
// try/catch block handles any errors --
// except we just ignore the errors since we
// are not anticipating any. What's wrong with
// that? We are perfect programmers and
// our users neve make mistakes! ;-)
public boolean action(Event evt, Object whatAction)
{
Integer intStr;
try
{
intStr = new Integer(getText());
intValue.setValue(intStr.intValue());
}
catch (Exception oops)
{ }
return true;
}
// update the value of the IntTextField when observed
// integer value changes
public void update(Observable obs, Object arg)
{
setText(""+intValue.getValue());
}
}
*** ObservableInt.java
// ObservableInt
import java.util.*;
public class ObservableInt extends Observable
{
// variable to store the data of interest
int value;
// constructor; if no value is provided, the
// variable is initialized to 0
public ObservableInt()
{
value = 0;
}
// constructor which takes an initial value
public ObservableInt(int newValue)
{
value = newValue;
}
// a syncronized method to update the value of the
// observed variable. By being synchronized,
// only one observer can be executing this handler
// at any given time. Therefore, we don't have to
// worry about the possibilty of two things changing
// the variable at the same time, resulting in
// corrupted data. One of the beauties of Java...
// add the one keyword and a lot of work is saved
// the programmer. (We only tell others that the
// value changed if it really changed.)
public synchronized void setValue(int newValue)
{
if (newValue != value)
{
value = newValue;
setChanged();
notifyObservers();
}
}
// Another synchronized method, this one to return
// the value of the observed variable. It is
// syncronized because only one synchronized
// method of a given object can be executed at
// any one time. Therefore, we also do not need
// to worry about somebody writing to the variable
// while somebody else is reading.
public synchronized int getValue()
{
return value;
}
}
*** ObservableString.java
// ObservableString -- almost identical to the ObservableInt,
// except we're dealing with a String instead of an
// Integer. I don't really want to retype the same
// boring comments, so just look at the comments in the
// ObservableInt.java file and leave me alone!
import java.util.*;
public class ObservableString extends Observable
{
String value;
public ObservableString()
{
value = null;
}
public ObservableString(String newValue)
{
value = newValue;
}
public synchronized void setValue(String newValue)
{
if (newValue != value)
{
value = newValue;
setChanged();
notifyObservers();
}
}
public synchronized String getValue()
{
return value;
}
}
*** StringTextField.java
// StringTextField -- essentially the same as IntTextField,
// so I direct you there for documentation and commentary
// as I'm not about to duplicate them here.
import java.awt.*;
import java.util.*;
public class StringTextField extends TextField implements Observer
{
private ObservableString StringValue;
public StringTextField(ObservableString theString)
{
super(""+theString.getValue());
StringValue = theString;
StringValue.addObserver(this);
}
public StringTextField(ObservableString theString, int size)
{
super(""+theString.getValue(),size);
StringValue = theString;
StringValue.addObserver(this);
}
public boolean action(Event evt, Object whatAction)
{
String StringStr;
try
{
StringStr = new String(getText());
StringValue.setValue(StringStr);
}
catch (Exception oops)
{ }
return true;
}
public void update(Observable obs, Object arg)
{
setText(""+StringValue.getValue());
}
}
*** qcSys.c
// qcSys -- the all important C function, to allow access to the QuickCam
// this source code, along with some other autogenerated and
// system standard headers, etc. are compiled into a shared library
// which is loaded by the Java system to provide access to the
// function in this file
// we need some standard Java (StubPreamble) and C (stdio) header files
#include <StubPreamble.h>
#include <stdio.h>
// and the header file for the native function, generated by the javah
// program, which is part of the JDK
#include "SrDesign.h"
// the function, with header as javah (and Java) understands it
// Java structures are accessed via the unhand() call which
// provides us with a pointer to the Java structure.
// A Java byte array is equivalent to a C char array
// The function operates by opening a pipe from the command
// requested by the main (run) loop and fget'ting that data
// into a character array
void SrDesign_qcSys(struct HSrDesign *this,
struct Hjava_lang_String *command,
HArrayOfByte *byteImage)
{
char *QCimage = unhand(byteImage)->body;
int length = obj_length(byteImage);
FILE *fp;
fp = popen(makeCString(command),"r");
fgets(QCimage, length, fp);
return;
}
*** SrDesign.java
// SrDesign -- the main body of code for the video conferencing
// portion of the Intelligent Video Conferencing project
// Copyright 1996-1997, Apu <apu@spfld.com> and Joanna Welenc
// Created for Stevens Institute of Technology EE/CS 415/416
// Dr. Stanley Smith, Advisor
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.net.*;
public class SrDesign extends Applet implements Runnable
{
// global variables
Thread animThread;
ObservableInt brightness, contrast, whitebal;
ObservableString remoteAddr;
Frame ControlPanel;
Image qcLocal, qcRemote;
byte[] byteImgLocal = new byte[24475];
byte[] byteImgRemote = new byte[24475];
static boolean inApplet=true;
// application startup
public static void main(String args[])
{
inApplet = false;
Frame applFrame = new Frame("SrDesign");
Applet SDappl = new SrDesign();
SDappl.init();
SDappl.start();
applFrame.setLayout(new FlowLayout());
applFrame.add(SDappl);
applFrame.resize(640,240);
applFrame.show();
}
// initialization
public void init()
{
// default values
brightness = new ObservableInt(135);
contrast = new ObservableInt(215);
whitebal = new ObservableInt(150);
remoteAddr = new ObservableString("localhost");
// create and add Control Panel frame
ControlPanel = ControlPanel("SrDesign - Controls");
}
public void start()
{
// start animation Thread
if (animThread == null)
{
animThread = new Thread(this);
animThread.start();
}
}
public void stop()
{
// stop animation Thread -- called by system on stopping
animThread.stop();
animThread = null;
}
// what do we repaint
public void paint(Graphics g)
{
g.drawImage(qcLocal, 0, 0, this);
g.drawImage(qcRemote, 320, 0, this);
}
// the main loop of the program
public void run()
{
// the command sent to the C library is stored
// in a local string
String command;
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
while (true)
{
try
{
// sleep for a while to let other stuff
// do its thing
animThread.sleep(100);
// Construct command string with current
// values of the the observables
// and get image
command = "qcam " +
" -b " + brightness.getValue() +
" -c " + contrast.getValue() +
" -w " + whitebal.getValue() +
" | ppmtogif";
qcSys(command, byteImgLocal);
qcLocal = createImage(new
MemoryImageSource(
320, 240,
ColorModel.getRGBdefault(),
byteImgLocal, 0, 0));
// send image to remote party
InetAddress internet_addr =
InetAddress.getByName(remoteAddr.getValue());
int port = 2000;
DatagramPacket snd_packet = new
DatagramPacket(
byteImgLocal, 24475,
internet_addr, port);
DatagramSocket snd_socket = new
DatagramSocket();
snd_socket.send(snd_packet);
snd_socket.close();
// and receive a frame from them
DatagramPacket rcv_packet = new
DatagramPacket(byteImgRemote,
byteImgRemote.length);
DatagramSocket rcv_socket = new
DatagramSocket(port);
rcv_socket.receive(rcv_packet);
rcv_socket.close();
// and now repaint both on screen
repaint();
}
catch (Exception sleepProblem)
{ }
}
}
// the qcSys function is implemented in native (non-Java) code
// we just need the prototype for others to use it
public native void qcSys(String command, byte[] byteImgLocal);
// (we need to load in the non-native code to be able to access it)
static
{
System.loadLibrary("qcSys");
}
// the ControlPanel is implemented as a separate frame so that
// we can collapse (minimize) it out of the way when we
// don't need it
private Frame ControlPanel(String label)
{
Frame frame = new Frame(label);
Panel panel;
IntScrollbar scrollbar;
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.WEST;
constraints.gridwidth = GridBagConstraints.REMAINDER;
frame.setLayout(gridbag);
panel = IntControl("Brightness",brightness);
gridbag.setConstraints(panel, constraints);
frame.add(panel);
scrollbar = new IntScrollbar(brightness,
Scrollbar.HORIZONTAL,
0, 10, 0, 255);
gridbag.setConstraints(scrollbar, constraints);
frame.add(scrollbar);
panel = IntControl("Contrast",contrast);
gridbag.setConstraints(panel, constraints);
frame.add(panel);
scrollbar = new IntScrollbar(contrast,
Scrollbar.HORIZONTAL,
0, 10, 0, 255);
gridbag.setConstraints(scrollbar, constraints);
frame.add(scrollbar);
panel = IntControl("White Balance",whitebal);
gridbag.setConstraints(panel, constraints);
frame.add(panel);
scrollbar = new IntScrollbar(whitebal,
Scrollbar.HORIZONTAL,
0, 10, 0, 255);
gridbag.setConstraints(scrollbar, constraints);
frame.add(scrollbar);
panel = StringControl("Remote Party",remoteAddr);
gridbag.setConstraints(panel, constraints);
frame.add(panel);
frame.resize(225,275);
frame.show();
return frame;
}
// parts for the ControlPanel implementing varies other classes
// remember, Java is an object-oriented language; the other
// classes are reusable, and hence not included as part of
// this file
private Panel IntControl(String label, ObservableInt variable)
{
Panel panel = new Panel();
panel.add(new Label(label));
panel.add(new IntTextField(variable));
return panel;
}
private Panel StringControl(String label, ObservableString variable)
{
Panel panel = new Panel();
Label lbl;
StringTextField field;
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridwidth = GridBagConstraints.REMAINDER;
panel.setLayout(gridbag);
lbl = new Label(label);
gridbag.setConstraints(lbl, constraints);
panel.add(lbl);
field = new StringTextField(variable);
gridbag.setConstraints(field, constraints);
panel.add(field);
return panel;
}
}