FileDocCategorySizeDatePackage
SunVideoSourceStream.javaAPI DocJMF 2.1.1e33747Mon May 12 12:21:26 BST 2003com.sun.media.protocol.sunvideo

SunVideoSourceStream

public class SunVideoSourceStream extends BasicSourceStream implements PushBufferStream, Owned
SourceStream for the DataSource The SourceStream can be accessed with the URL sunvideo: The URL has been extended to allow selecting some of the options: sunvideo://card/port/compression/size where card = the sunvideo card to use (default 0) when multiple cards are installed. port = port to use (default 1), s-vhs, 1, or 2. compression = rgb or jpeg (default jpeg). size = 1, 1/2, or 1/4 (default 1/2). Actual frame size depends on whether the camera is NTSC or PAL.

Fields Summary
private DataSource
dataSource
private MediaLocator
locator
int
maxDataSize
BufferTransferHandler
transferHandler
private byte[]
data
private int
length
private long
nextSequence
long
timeStamp
XILCapture
svCap
SystemTimeBase
systemTimeBase
private VideoFormat
capFormat
private static Format[]
supported
private static final boolean
CONTROL_PANEL_HACK
private Frame
controlFrame
private static Integer
SunVideoLock
Integer
readLock
private boolean
started
private boolean
connected
private boolean
connectedOK
private boolean
inUse
private int
cardNo
private static String[]
VALID_PORTS
private static final int
DEFAULT_PORT
private int
portNo
private static String[]
VALID_COMPRESS
private static String[]
VIDEO_COMPRESS
private static final int
DEFAULT_COMPRESS
private static final int
RGB_COMPRESS
private int
compressNo
private static String[]
VALID_SIZES
private static Dimension[]
DEFAULT_DIMENSIONS
private static float[]
VALID_SIZES_FLOAT
private static int[]
VALID_SCALE
private static final int
DEFAULT_SIZE
private static float
SIZE_GRANULARITY
private int
sizeNo
private static final int
DEFAULT_RATE
private int
rateNo
private static final int
DEFAULT_QUALITY
private int
qualityNo
private LocalPortControl
portControl
private RateControl
rateControl
private LocalQualityControl
qualityControl
private LocalFormatControl
formatControl
private float
preferredFrameRate
private PushThread
pt
long
ptDelay
private static JMFSecurity
jmfSecurity
private static boolean
securityPrivelege
private Method[]
mSecurity
private Class[]
clSecurity
private Object[]
argsSecurity
Constructors Summary
public SunVideoSourceStream(DataSource ds)


     
        try {
            jmfSecurity = JMFSecurityManager.getJMFSecurity();
            securityPrivelege = true;
        } catch (SecurityException e) {
        }

	supported = new javax.media.Format[] {

	    // NTSC
		    // JPEG formats
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.JPEG,
				new Dimension(320, 240),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.JPEG,
				new Dimension(160, 120),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),

		    // RGB formats
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(640, 480),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(320, 240),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(160, 120),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),

	    // PAL
		    // JPEG formats
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.JPEG,
				new Dimension(384, 288),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.JPEG,
				new Dimension(192, 144),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),

		    // RGB formats
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(768, 576),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(384, 288),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),
		    new javax.media.format.VideoFormat(
				javax.media.format.VideoFormat.RGB,
				new Dimension(192, 144),
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				javax.media.format.VideoFormat.NOT_SPECIFIED),

	};
    
	super(new ContentDescriptor(ContentDescriptor.RAW),
	      LENGTH_UNKNOWN);
	this.dataSource = ds;
	this.locator = ds.getLocator();
	cardNo = 0;
	String remainder = locator.getRemainder();
	if (remainder != null && remainder.length() > 0) {
	    while (remainder.length() > 1 && remainder.charAt(0) == '/")
		remainder = remainder.substring(1);
	    String cardStr, portStr, compStr, sizeStr;
	    portStr = null;		// assume no port specified
	    compStr = null;		// assume no compress specified
	    sizeStr = null;		// assume no size specified
	    // Now see if there's a port specified.
	    int off = remainder.indexOf('/");
	    if (off == -1) {
		cardStr = remainder;
	    } else {
		cardStr = remainder.substring(0, off);
		remainder = remainder.substring(off + 1);
		// Now see if there's a compression specified
		off = remainder.indexOf('/");
		if (off == -1) {
		    portStr = remainder;
		} else {
		    portStr = remainder.substring(0, off);
		    remainder = remainder.substring(off + 1);
		    // Now see if there's a size specified
		    off = remainder.indexOf('/");
		    if (off == -1) {
			compStr = remainder;
		    } else {
			compStr = remainder.substring(0, off);
			sizeStr = remainder.substring(off + 1);
		    }
		}
	    }
	    try {
		Integer integer = Integer.valueOf(cardStr);
		if (integer != null) {
		    cardNo = integer.intValue();
		}
	    } catch (Throwable t) {
	    }
	    if (portStr != null && portStr.length() > 0) {
		for (int i = 0; i < VALID_PORTS.length; i++) {
		    if (VALID_PORTS[i].equalsIgnoreCase(portStr)) {
			portNo = i;
		    }
		}
	    }
	    if (compStr != null && compStr.length() > 0) {
		for (int i = 0; i < VALID_COMPRESS.length; i++) {
		    if (VALID_COMPRESS[i].equalsIgnoreCase(compStr)) {
			compressNo = i;
		    }
		}
	    }
	    if (sizeStr != null && sizeStr.length() > 0) {
		for (int i = 0; i < VALID_SIZES.length; i++) {
		    if (VALID_SIZES[i].equalsIgnoreCase(sizeStr)) {
			sizeNo = i;
		    }
		}
	    }
	}
	capFormat = new javax.media.format.VideoFormat(
				VIDEO_COMPRESS[compressNo],
				DEFAULT_DIMENSIONS[sizeNo],
				javax.media.format.VideoFormat.NOT_SPECIFIED,
				Format.byteArray,
				getRate());
	svCap = new XILCapture(this);

	portControl = new LocalPortControl(this, VALID_PORTS, portNo);
	rateControl = new RateControl(this, (float)DEFAULT_RATE, 1f, 30f);
	qualityControl = new LocalQualityControl(this,
						((float)DEFAULT_QUALITY/100f),
						0.01f, 0.62f);

	formatControl = new LocalFormatControl(this);

	controls = new Object[4];
	controls[0] = portControl;
	controls[1] = rateControl;
	controls[2] = qualityControl;
	controls[3] = formatControl;
    
Methods Summary
public voidconnect()

	synchronized (SunVideoLock) {
	    if (inUse) {
		throw new IOException("Capture device in use");
	    } else
		inUse = true;
	    connected = false;
	    if (!doConnect()) {
		inUse = false;
		throw new IOException("Could not connect to capture device");
	    }
	    connected = true;
	}

	// Following only needed while the control frame hack is present...
	if (CONTROL_PANEL_HACK)
	    doControlPanelHack();
	// Preceding only needed while the control frame hack is present...
    
synchronized voiddisconnect()

	//	System.err.println("SunVideoSourceStream.disconnect");
	if (started) {
	    try {
		stop();
	    } catch (IOException ioe) {
	    }
	}
	synchronized (SunVideoLock) {
	    connected = false;
	    svCap.disconnect();
	    pt = null;
	    inUse = false;
	}

	// Following only needed while the control frame hack is present...
	if(CONTROL_PANEL_HACK && controlFrame != null) {
	    controlFrame.setVisible(false);
	    controlFrame.removeAll();
	    controlFrame.dispose();
	    controlFrame = null;
	}
	// Preceding only needed while the control frame hack is present...
    
private booleandoConnect()

	//	System.err.println("SunVideoSourceStream.doConnect");
	if (!svCap.connect(cardNo, portNo))
	    return false;
	setSize(sizeNo);		// set the scale
	setCompress(compressNo);	// set the compression

	data = new byte[maxDataSize];	// prime the data field for push
	nextSequence = 1;		// reset in case it's a reconnect
	return true;
    
private voiddoControlPanelHack()

	if (controlFrame != null) {
	    controlFrame.setVisible(true);
	    return;
	}
	controlFrame = new Frame("SunVideo Controls");
	controlFrame.addWindowListener(new WindowAdapter() {
	    public void windowClosing(WindowEvent e) {
		controlFrame.setVisible(false);
	    }
	});
	controlFrame.setLayout(new BorderLayout());
	Panel p = new Panel();
	p.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 1));
	//	p.add(new LabelComponent("Port"));
	p.add(portControl.getControlComponent());
	//	p.add(new LabelComponent("Format"));
	p.add(formatControl.getControlComponent());
	controlFrame.add(p, "North");
	p = new Panel();
	p.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 1));
	p.add(rateControl.getControlComponent());
	p.add(qualityControl.getControlComponent());
	controlFrame.add(p, "South");
	controlFrame.pack();
	controlFrame.setVisible(true);
    
public voidfinalize()

	if (connected)
	    disconnect();
    
public javax.media.CaptureDeviceInfogetCaptureDeviceInfo()

	// TODO - more useful descriptor of device
	return new CaptureDeviceInfo("SunVideo", locator, supported);
    
booleangetConnected()

	return connected;
    
byte[]getData()

	return data;
    
public java.lang.ObjectgetDataType()

	return Format.byteArray;
    
public javax.media.FormatgetFormat()

	//	System.err.println("SunVideoSourceStream.getFormat");
	return capFormat;
    
public java.lang.ObjectgetOwner()
Owned

	return dataSource;
    
floatgetQuality()

	return ((float) qualityNo / 100f);
    
floatgetRate()

	if (rateNo == 30)
	    return 29.97f;	// NTSC standard broadcast frame rate
	return (float) rateNo;
    
intgetSize()

	return sizeNo;
    
floatgetSizeFloat()

	return VALID_SIZES_FLOAT[sizeNo];
    
float[]getSizesFloat()

	return VALID_SIZES_FLOAT;
    
booleangetStarted()

	return started;
    
public javax.media.Format[]getSupportedFormats()

	//	System.err.println("SunVideoSourceStream.getSupportedFormats");
	return supported;
    
voidpushData(int length)

	this.length = length;
	if (transferHandler != null)
	    transferHandler.transferData(this);
    
public voidread(javax.media.Buffer buffer)

	//	System.err.println("SunVideoSourceStream.read");
	if (!started) {
	    buffer.setDiscard(true);
	    length = 0;
	    return;
	}
	synchronized (readLock) {
	    if (length > 0) {
		byte [] outgoingData = data;
		Object incomingData = buffer.getData();
		if (incomingData instanceof byte[] &&
		    ((byte[])incomingData).length >= maxDataSize) {
		    data = (byte []) incomingData;
		} else {
		    data = new byte[maxDataSize];
		}
		buffer.setOffset(0);
		buffer.setData(outgoingData);
		buffer.setLength(length);
		buffer.setDiscard(false);
		buffer.setSequenceNumber(nextSequence++);
		buffer.setTimeStamp(timeStamp);
		buffer.setFlags(buffer.getFlags() |
				buffer.FLAG_SYSTEM_TIME |
				buffer.FLAG_KEY_FRAME |
				buffer.FLAG_LIVE_DATA);
		buffer.setFormat(capFormat);
	    } else
		buffer.setDiscard(true);
	    length = 0;
	}
    
private voidsetCompress(java.lang.String compress)

	if (compress != null && compress.length() > 0) {
	    for (int i = 0; i < VALID_COMPRESS.length; i++) {
		if (VALID_COMPRESS[i].equalsIgnoreCase(compress)) {
		    compressNo = i;
		    if (connected)
			setCompress(compressNo);
		}
	    }
	}
    
private voidsetCompress(int compress)

	compressNo = compress;
	svCap.setCompress(VALID_COMPRESS[compressNo]);
	if (compress == RGB_COMPRESS) {
	    qualityControl.setEnabled(false);
	} else {
	    qualityControl.setEnabled(true);
	}
    
voidsetData(byte[] buf)

	data = buf;
    
public javax.media.FormatsetFormat(javax.media.Format fmt)


	if (fmt.equals(capFormat))
	    return capFormat;

	//System.err.println("SunVideoSourceStream.setFormat() format: " + fmt);
	javax.media.Format f = null;
	for (int i = 0; i < supported.length; i++) {
	    if (fmt.matches(supported[i]) &&
		(f = fmt.intersects(supported[i])) != null) {
		break;
	    }
	}

	if (f != null) {
	    VideoFormat format = (javax.media.format.VideoFormat)f;
	    if (format.getEncoding().equals(format.JPEG)) {
		setCompress("Jpeg");
	    } else {
		setCompress("RGB");
	    }
	    if (format.getFrameRate() !=
				javax.media.format.VideoFormat.NOT_SPECIFIED) {
		// rateControl will call back to setRate
		rateControl.setFrameRate(format.getFrameRate());
	    }
	    setSize(format.getSize());
	    if (!connected) {
		capFormat = format;
	    }
	}

	return capFormat;
    
public voidsetJpegFormat(int inWidth, int inHeight, int outWidth, int outHeight, int quality)

	if (inWidth <= 0) inWidth = 640;	// default to NTSC
	if (inHeight <= 0) inHeight = 480;	// default to NTSC
	if (outWidth <= 0) outWidth = inWidth / VALID_SCALE[sizeNo];
	if (outHeight <= 0) outHeight = inHeight / VALID_SCALE[sizeNo];

	Dimension dim = new java.awt.Dimension(outWidth, outHeight);
	if (quality > 60)
	    maxDataSize = 3 * outWidth * outHeight;
	else
	    maxDataSize = 2 * outWidth * outHeight;
	capFormat = new JPEGFormat(dim, maxDataSize, Format.byteArray,
				getRate(), qualityNo, JPEGFormat.NOT_SPECIFIED);

	formatControl.setCurrentFormat(capFormat);
    
public voidsetMpegFormat(int inWidth, int inHeight, int outWidth, int outHeight, int quality)

	if (inWidth <= 0) inWidth = 640;	// default to NTSC
	if (inHeight <= 0) inHeight = 480;	// default to NTSC
	if (outWidth <= 0) outWidth = inWidth / VALID_SCALE[sizeNo];
	if (outHeight <= 0) outHeight = inHeight / VALID_SCALE[sizeNo];

	Dimension dim = new java.awt.Dimension(outWidth, outHeight);
	if (quality > 60)
	    maxDataSize = 3 * outWidth * outHeight;
	else
	    maxDataSize = 2 * outWidth * outHeight;
	capFormat = new VideoFormat(VideoFormat.MPEG, dim,
				    maxDataSize, Format.byteArray,
				    getRate()); // frame rate

	formatControl.setCurrentFormat(capFormat);
    
private voidsetPort(int port)

	portNo = port;
	svCap.setPort(portNo);
    
voidsetQuality(float quality)

	qualityNo = (int) ((quality * 100f) + 0.5f);
	svCap.setQuality(qualityNo);
	if ((capFormat != null) && (capFormat instanceof JPEGFormat)) {
	    capFormat = new JPEGFormat(
			(capFormat == null ? null : capFormat.getSize()), 
			maxDataSize, Format.byteArray, getRate(),
			qualityNo, JPEGFormat.NOT_SPECIFIED);
	}
    
public voidsetRGBFormat(int inWidth, int inHeight, int outWidth, int outHeight, int scanLine)

	if (inWidth <= 0) inWidth = 640;	// default to NTSC
	if (inHeight <= 0) inHeight = 480;	// default to NTSC
	if (outWidth <= 0) outWidth = inWidth / VALID_SCALE[sizeNo];
	if (outHeight <= 0) outHeight = inHeight / VALID_SCALE[sizeNo];

	Dimension dim = new java.awt.Dimension(outWidth, outHeight);
	// media engine doesn't like NOT_SPECIFIED
	if (scanLine == Format.NOT_SPECIFIED)
	    scanLine = 3 * outWidth;
	maxDataSize = scanLine * outHeight;
	capFormat = new RGBFormat(dim, maxDataSize, Format.byteArray,
				  getRate(), // frame rate
				  24,
				  3, 2, 1, 3, scanLine,
				  Format.FALSE, // flipped
				  Format.NOT_SPECIFIED); // endian
	formatControl.setCurrentFormat(capFormat);
    
voidsetRate(float rate)

	rateNo = (int) (rate + 0.5);
	if (rateNo <= 0)
	    rateNo = 1;
	ptDelay = 1000 / rateNo;
	//System.err.println("SunVideoSourceStream.setRate() rate: " + rateNo);

	// Adjust frame rate in format
	if (capFormat != null) {
	    if (VideoFormat.JPEG.equals(capFormat.getEncoding())) {
		capFormat = new JPEGFormat(capFormat.getSize(), 
			maxDataSize, Format.byteArray, getRate(),
			qualityNo, JPEGFormat.NOT_SPECIFIED);
	    } else if (VideoFormat.RGB.equals(capFormat.getEncoding())) {
		capFormat = new RGBFormat(capFormat.getSize(), 
			maxDataSize, Format.byteArray,
			getRate(), // frame rate
			24,
			3, 2, 1, 3,
			((RGBFormat)capFormat).getLineStride(),
			Format.FALSE, // flipped
			Format.NOT_SPECIFIED); // endian
	    }else if (VideoFormat.MPEG.equals(capFormat.getEncoding())) {
		capFormat = new VideoFormat(VideoFormat.MPEG,
			capFormat.getSize(), 
			maxDataSize, Format.byteArray,
			getRate()); // frame rate

	    }
	    formatControl.setCurrentFormat(capFormat);
	}
    
voidsetSize(java.awt.Dimension size)

	int scale = 1;

	// Handle both NTSC and PAL sizes
	if (size.width > 384)
	    scale = 1;
	else if (size.width >= 320)
	    scale = 2;
	else
	    scale = 4;

	for (int i = 0; i < VALID_SIZES.length; i++) {
	    if (VALID_SCALE[i] == scale) {
		sizeNo = i;
		if (connected)
		    setSize(sizeNo);
	    }
	}
    
voidsetSize(int size)

	sizeNo = size;
	svCap.setScale(VALID_SCALE[sizeNo]);
    
voidsetSize(float size)

	if (size > VALID_SIZES_FLOAT[0]) {
	    sizeNo = 0;
	} else {
	    for (int i = 1; i < VALID_SIZES_FLOAT.length; i++) {
		sizeNo = i;
		if (size > VALID_SIZES_FLOAT[i]) {
		    // Allow for the cases where size is not an exact match
		    if ((VALID_SIZES_FLOAT[i - 1] - size) <
					    (size - VALID_SIZES_FLOAT[i])) {
			sizeNo = i - 1;
			break;
		    }
		    break;
		}
	    }
	}
	svCap.setScale(VALID_SCALE[sizeNo]);
    
public voidsetTransferHandler(javax.media.protocol.BufferTransferHandler th)

	transferHandler = th;
    
voidstart()

	//	System.err.println("SunVideoSourceStream.start");
	if (started)
	    return;
	if (!svCap.start()) {
	    //	System.err.println("SunVideoSourceStream.start failed");
	    throw (new IOException("SunVideoStart failed"));
	}
	synchronized (this) {
	    started = true;
	    
	    // Start the video call back polling thread
	    if (pt == null) {
		if ( /*securityPrivelege  && */ (jmfSecurity != null) ) {
		    String permission = null;
		    try {
			if (jmfSecurity.getName().startsWith("jmf-security")) {
			    permission = "thread";
			    jmfSecurity.requestPermission(mSecurity, clSecurity, argsSecurity,
							  JMFSecurity.THREAD);
			    mSecurity[0].invoke(clSecurity[0], argsSecurity[0]);
			    
			    permission = "thread group";
			    jmfSecurity.requestPermission(mSecurity, clSecurity, argsSecurity,
							  JMFSecurity.THREAD_GROUP);
			    mSecurity[0].invoke(clSecurity[0], argsSecurity[0]);
			} else if (jmfSecurity.getName().startsWith("internet")) {
			    PolicyEngine.checkPermission(PermissionID.THREAD);
			    PolicyEngine.assertPermission(PermissionID.THREAD);
			}
		    } catch (Throwable e) {
       			if (JMFSecurityManager.DEBUG) {
        	            System.err.println( "Unable to get " + permission +
	        		     	        " privilege  " + e);
                        }
			securityPrivelege = false;
			// TODO: Do the right thing if permissions cannot be obtained.
			// User should be notified via an event
		    }
		}

		if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) {
		    try {
			Constructor cons = jdk12CreateThreadAction.cons;

			pt = (PushThread) jdk12.doPrivM.invoke(
                                           jdk12.ac,
					   new Object[] {
 					  cons.newInstance(
 					   new Object[] {
                                               PushThread.class,
                                               this
                                           })});


		    } catch (Exception e) {
			System.err.println("SunVideoSourceStream: exception when creating thread");
		    }
		} else {
		    pt = new PushThread(this);
		}

		if (pt != null) {
		    pt.start();
		}
	    }

	    if (formatControl != null) formatControl.getControlComponent().
							setEnabled(false);
	    
	}
    
voidstop()

	//	System.err.println("SunVideoSourceStream.stop");
	started = false;
	svCap.stop();

	if (portControl != null) portControl.setEnabled(true);

	if (formatControl != null) formatControl.getControlComponent().
							setEnabled(true);
    
public booleanwillReadBlock()

	return true;