/*
* @(#)MonitorAdapter.java 1.24 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.media.controls;
import javax.media.*;
import javax.media.format.*;
import javax.media.control.MonitorControl;
import java.awt.Component;
import java.awt.Container;
import java.awt.Panel;
import java.awt.BorderLayout;
import java.awt.PopupMenu;
import java.awt.MenuItem;
import java.awt.Checkbox;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.*;
import com.sun.media.CircularBuffer;
import com.sun.media.Log;
import com.sun.media.util.*;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import com.sun.media.JMFSecurity;
import com.sun.media.JMFSecurityManager;
import com.ms.security.PermissionID;
import com.ms.security.PolicyEngine;
public class MonitorAdapter implements MonitorControl, Owned {
protected CodecChain cc = null;
protected boolean enabled = false;
protected boolean closed = false;
protected Component visualComponent = null;
protected Component controlComponent = null;
protected Checkbox cbEnabled = null;
protected Format format = null;
protected float inFrameRate = 0f;
protected float previewFrameRate = 30f;
protected long lastPreviewTime = 0;
protected long previewInterval = 1000000000L / 30;
protected MouseListener ml = null;
protected PopupMenu rateMenu = null;
protected LoopThread loopThread;
protected int [] frameRates = {0, 1, 2, 5, 7, 10, 15, 20, 30, 60, 90};
CircularBuffer bufferQ;
Object owner;
/* some JMFSecurity stuff */
private static JMFSecurity jmfSecurity = null;
private static boolean securityPrivelege=false;
private Method mSecurity[] = new Method[1];
private Class clSecurity[] = new Class[1];
private Object argsSecurity[][] = new Object[1][0];
// For comparing formats.
static VideoFormat mpegVideo = new VideoFormat(VideoFormat.MPEG_RTP);
static {
try {
jmfSecurity = JMFSecurityManager.getJMFSecurity();
securityPrivelege = true;
} catch (SecurityException e) {
}
}
public MonitorAdapter(Format f, Object owner) {
format = f;
this.owner = owner;
}
protected boolean open() {
try {
if (format instanceof VideoFormat) {
VideoFormat vf = (VideoFormat)format;
cc = new VideoCodecChain(vf);
inFrameRate = vf.getFrameRate();
if (inFrameRate < 0) // if unspecified
inFrameRate = 30f;
inFrameRate = ((int)(inFrameRate * 10 + 0.5)) / 10f;
} else if (format instanceof AudioFormat) {
cc = new AudioCodecChain((AudioFormat)format);
}
} catch (UnsupportedFormatException e) {
Log.warning("Failed to initialize the monitor control: " + e);
return false;
}
if (cc == null)
return false;
bufferQ = new CircularBuffer(2);
if ( 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 = CreateWorkThreadAction.cons;
loopThread = (MonitorThread) jdk12.doPrivM.invoke(
jdk12.ac,
new Object[] {
cons.newInstance(
new Object[] {
MonitorThread.class,
MonitorAdapter.class,
this
})});
} catch (Exception e) {
}
} else {
loopThread = new MonitorThread(this);
}
return true;
}
public Object getOwner() {
return owner;
}
public boolean setEnabled(boolean on) {
if (on) {
if (cc == null) {
if (!open())
return false;
} else
cc.reset();
if (!cc.prefetch())
return false;
// Flush the bufferQ.
synchronized (bufferQ) {
while (bufferQ.canRead()) {
bufferQ.read();
bufferQ.readReport();
}
}
enabled = true;
loopThread.start();
} else if (!on && cc != null) {
loopThread.pause();
// In case we are blocked at the process call.
synchronized (bufferQ) {
enabled = false;
bufferQ.notifyAll();
}
cc.deallocate();
}
return enabled;
}
public boolean isEnabled() {
return enabled;
}
public void reset() {
if (cc != null)
cc.reset();
}
public void close() {
if (cc == null)
return;
loopThread.kill();
synchronized (bufferQ) {
closed = true;
bufferQ.notifyAll();
}
cc.close();
cc = null;
}
public void process(Buffer input) {
if (input == null || previewFrameRate <= 0 ||
format == null || input.isEOM() || input.isDiscard() ||
(input.getFlags() & input.FLAG_FLUSH) != 0) {
return;
}
if (!format.matches(input.getFormat())) {
return;
}
Buffer buffer = null;
// Grab an empty buffer from the queue.
synchronized (bufferQ) {
while (!bufferQ.canWrite() && enabled && !closed) {
try {
bufferQ.wait();
} catch (Exception e) {}
}
if (!enabled || closed)
return;
buffer = bufferQ.getEmptyBuffer();
}
// expensive copy
buffer.setData(copyData(input.getData()));
buffer.setFlags(input.getFlags());
buffer.setFormat(input.getFormat());
buffer.setSequenceNumber(input.getSequenceNumber());
buffer.setHeader(input.getHeader());
buffer.setLength(input.getLength());
buffer.setOffset(input.getOffset());
buffer.setTimeStamp(input.getTimeStamp());
// Put the buffer into the queue.
synchronized (bufferQ) {
bufferQ.writeReport();
bufferQ.notifyAll();
}
}
public boolean doProcess() {
Buffer buffer;
// Grab a filled buffer from the queue.
synchronized (bufferQ) {
while (!bufferQ.canRead() && enabled && !closed) {
try {
bufferQ.wait();
} catch (Exception e) {}
}
if (closed)
return false;
else if (!enabled)
return true;
buffer = bufferQ.read();
}
boolean toDisplay = false;
if (buffer.getFormat() instanceof AudioFormat) {
toDisplay = true;
} else {
long time = buffer.getTimeStamp();
if (time >= lastPreviewTime + previewInterval ||
time <= lastPreviewTime) {
if (mpegVideo.matches(format)) {
/*
* Only set toDisplay true on MPEG I frames.
* This way VideoCodecChain can treat the stream
* as a raw format and avoid overloading the
* CPU by sending every frame to the decoder.
* Downside is it limits the framerate that can
* be set for the monitor.
*/
byte[] payload = (byte[])buffer.getData();
int offset = buffer.getOffset();
int ptype = payload[offset+2] & 0x07;
if (ptype == 1) {
lastPreviewTime = time;
toDisplay = true;
}
} else {
lastPreviewTime = time;
toDisplay = true;
}
} else
toDisplay = false;
}
// Use the codec chain to process the data.
cc.process(buffer, toDisplay);
// Return the processed buffer back to the queue.
synchronized (bufferQ) {
bufferQ.readReport();
bufferQ.notifyAll();
}
return true;
}
private Object copyData(Object in) {
if (in instanceof byte[]) {
byte [] out = new byte[((byte[])in).length];
System.arraycopy(in, 0, out, 0, out.length);
return out;
}
if (in instanceof short[]) {
short [] out = new short[((short[])in).length];
System.arraycopy(in, 0, out, 0, out.length);
return out;
}
if (in instanceof int[]) {
int [] out = new int[((int[])in).length];
System.arraycopy(in, 0, out, 0, out.length);
return out;
}
return in;
}
public float setPreviewFrameRate(float value) {
if (value > inFrameRate)
value = inFrameRate;
previewFrameRate = value;
previewInterval = (long) (1E+9 / value);
return value;
}
public Component getControlComponent() {
/*
if (controlComponent == null) {
if (cc != null)
visualComponent = getVisualComponent();
if (visualComponent == null)
return null;
southPanel = new Panel();
listBox = new List(6);
for (int i = 0; i <= inFrameRate; i++) {
listBox.add(i + " fps");
}
southPanel.add(new Label("Monitor Frame Rate : "));
southPanel.add(listBox);
preferredSize = visualComponent.getPreferredSize();
preferredSize.height += southPanel.getPreferredSize().height;
controlComponent = new Panel(new BorderLayout()) {
public Dimension getPreferredSize() {
return preferredSize;
}
};
controlComponent.add("Center", visualComponent);
controlComponent.add("South", southPanel);
}
*/
if (controlComponent != null)
return controlComponent;
if (cc == null && !open())
return null;
controlComponent = cc.getControlComponent();
// Create Audio Monitor Panel
if (format instanceof AudioFormat && controlComponent != null) {
Container controlPanel = new Panel();
controlPanel.setLayout( new BorderLayout() );
cbEnabled = new Checkbox("Monitor Audio");
controlPanel.add("West", cbEnabled);
controlPanel.add("Center", controlComponent);
controlComponent = controlPanel;
controlPanel.setBackground ( java.awt.Color.lightGray );
}
if (format instanceof VideoFormat && controlComponent != null) {
Container controlPanel = new Panel();
controlPanel.setLayout( new BorderLayout() );
cbEnabled = new Checkbox("Monitor Video");
controlPanel.add("South", cbEnabled);
controlPanel.add("Center", controlComponent);
addPopupMenu(controlComponent);
controlComponent = controlPanel;
controlPanel.setBackground ( java.awt.Color.lightGray );
}
if (cbEnabled != null) {
cbEnabled.setState(isEnabled());
cbEnabled.addItemListener( new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
MonitorAdapter.this.setEnabled(cbEnabled.getState());
}
} );
}
//
return controlComponent;
}
private void addPopupMenu(Component visual) {
MenuItem mi;
ActionListener rateSelect;
visualComponent = visual;
rateMenu = new PopupMenu("Monitor Rate");
rateSelect = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String action = ae.getActionCommand();
int space = action.indexOf(" ");
String rateString = action.substring(0, space);
try {
int rate = Integer.parseInt(rateString);
setPreviewFrameRate((float)rate);
} catch (Throwable t) {
if (t instanceof ThreadDeath)
throw (ThreadDeath) t;
}
}
};
visual.add(rateMenu);
int lastAdded = 0;
for (int i = 0; i < frameRates.length; i++) {
if (frameRates[i] < inFrameRate) {
mi = new MenuItem(frameRates[i] + " fps");
rateMenu.add(mi);
mi.addActionListener(rateSelect);
lastAdded = frameRates[i];
}
}
if (lastAdded < inFrameRate) {
mi = new MenuItem(inFrameRate + " fps");
rateMenu.add(mi);
mi.addActionListener(rateSelect);
}
visual.addMouseListener( ml = new MouseAdapter() {
public void mousePressed(MouseEvent me) {
if (me.isPopupTrigger())
rateMenu.show(visualComponent, me.getX(), me.getY());
}
public void mouseReleased(MouseEvent me) {
if (me.isPopupTrigger())
rateMenu.show(visualComponent, me.getX(), me.getY());
}
public void mouseClicked(MouseEvent me) {
if (me.isPopupTrigger())
rateMenu.show(visualComponent, me.getX(), me.getY());
}
} );
}
public void finalize() {
if (visualComponent != null) {
visualComponent.remove(rateMenu);
visualComponent.removeMouseListener(ml);
}
}
//////////////////////////////////
//
// Inner class
//////////////////////////////////
}
class MonitorThread extends LoopThread {
MonitorAdapter ad;
public MonitorThread(MonitorAdapter ad) {
setName(getName() + " : MonitorAdapter");
useVideoPriority();
this.ad = ad;
}
protected boolean process() {
return ad.doProcess();
}
}
|