📄 datasource.java
字号:
package net.sf.fmj.media.protocol.civil;import java.awt.Component;import java.awt.Dimension;import java.io.IOException;import java.io.InterruptedIOException;import java.util.List;import java.util.logging.Level;import java.util.logging.Logger;import javax.media.Buffer;import javax.media.CaptureDeviceInfo;import javax.media.Format;import javax.media.Time;import javax.media.control.FormatControl;import javax.media.format.RGBFormat;import javax.media.format.VideoFormat;import javax.media.protocol.BufferTransferHandler;import javax.media.protocol.CaptureDevice;import javax.media.protocol.ContentDescriptor;import javax.media.protocol.PushBufferDataSource;import javax.media.protocol.PushBufferStream;import net.sf.fmj.utility.FPSCounter;import net.sf.fmj.utility.LoggerSingleton;import com.lti.civil.CaptureException;import com.lti.civil.CaptureObserver;import com.lti.civil.CaptureStream;import com.lti.civil.CaptureSystem;import com.lti.civil.CaptureSystemFactory;import com.lti.civil.DefaultCaptureSystemFactorySingleton;import com.lti.civil.Image;import com.lti.utils.synchronization.CloseableThread;import com.lti.utils.synchronization.ProducerConsumerQueue;import com.lti.utils.synchronization.SynchronizedBoolean;import com.lti.utils.synchronization.SynchronizedObjectHolder;import com.lti.utils.synchronization.ThreadGroupMgr;/** * DataSource for CIVIL video. * @author Ken Larson * */public class DataSource extends PushBufferDataSource implements CaptureDevice{ private static final boolean TRACE = true; private static final Logger logger = LoggerSingleton.logger; private CaptureSystem system; private String deviceId; private CaptureStream captureStream; private MyPushBufferStream pushBufferStream; /** * The JMF video output format we are delivering. */ private VideoFormat outputVideoFormat = null; private boolean connected; private static final int BUFFER_QUEUE_SIZE = 2; // after this many items in queue, we will drop frames. // the frame dropping allows us to stay going in real-time. // TODO: this might not be good for some applications. // TODO: we are still dropping some frames even after // optimization. private final ProducerConsumerQueue bufferQueue = new ProducerConsumerQueue(BUFFER_QUEUE_SIZE);// private boolean bufferQueueEnabled = false; // synch on bufferQueue to use. if false, only 1 item is kept in buffer queue.// // this allows us to not buffer frames before we are reading them, to minimize the// // latency between the images coming in, and the images going out. private static final boolean TRACE_FPS = false; //@Override public void connect() throws IOException { if (TRACE) logger.fine("connect"); // Normally, we allow a re-connection even if we are connected, due to an oddity in the way Manager works. See comments there // in createPlayer(MediaLocator sourceLocator). // however, because capture devices won't go back to previous data even if we reconnect, there is no point in reconnecting. if (connected) return; try { CaptureSystemFactory factory = DefaultCaptureSystemFactorySingleton.instance(); system = factory.createCaptureSystem(); system.init(); // TODO: dispose of properly if (TRACE) logger.fine("Opening " + getLocator().getRemainder()); // see if it is an ordinal URL like civil:0 or civil:/0 final int ordinal = ordinal(getLocator().getRemainder()); if (ordinal >= 0) { deviceId = deviceIdFromOrdinal(ordinal); if (deviceId == null) throw new IOException("Unable to convert ordinal " + ordinal + " to a capture device"); } else { deviceId = getLocator().getRemainder(); } captureStream = system.openCaptureDeviceStream(deviceId); captureStream.getVideoFormat(); outputVideoFormat = convertCivilFormat(captureStream.getVideoFormat()); captureStream.setObserver(new MyCaptureObserver()); pushBufferStream = new MyPushBufferStream(); } catch (CaptureException e) { logger.log(Level.WARNING, "" + e, e); throw new IOException("" + e); } connected = true; } // handle ordinal locators, like civil:0 or civil:/0 private static int ordinal(String remainder) { try { // allow either with slash or without if (remainder.startsWith("/")) remainder = remainder.substring(1); return Integer.parseInt(remainder); } catch (Exception e) { return -1; } } private String deviceIdFromOrdinal(int index) throws CaptureException { final List list = system.getCaptureDeviceInfoList(); if (index < 0 || index >= list.size()) return null; com.lti.civil.CaptureDeviceInfo info = (com.lti.civil.CaptureDeviceInfo) list.get(index); return info.getDeviceID(); } //@Override public void disconnect() { if (TRACE) logger.fine("disconnect"); if (!connected) return; if (pushBufferStream != null) pushBufferStream.dispose(); try { stop(); } catch (IOException e) { logger.log(Level.WARNING, "" + e, e); } if (captureStream != null) { try { captureStream.dispose(); } catch (CaptureException e) { logger.log(Level.WARNING, "" + e, e); } finally { captureStream = null; } } connected = false; } private static final String CONTENT_TYPE = ContentDescriptor.RAW; //@Override public String getContentType() { return CONTENT_TYPE; // TODO: what should this be? } //@Override public Object getControl(String controlType) { return null; } //@Override public Object[] getControls() { return new Object[0]; } private final SynchronizedBoolean started = new SynchronizedBoolean(false); //@Override public void start() throws IOException { if (TRACE) logger.fine("start"); if (started.getValue()) { logger.warning("Civil DataSource.start called while already started, ignoring"); return; } try { captureStream.start(); } catch (CaptureException e) { logger.log(Level.WARNING, "" + e, e); throw new IOException("" + e); } started.setValue(true); } //@Override public void stop() throws IOException { if (TRACE) logger.fine("stop"); if (!started.getValue()) return; try { if (captureStream != null) { captureStream.stop(); } synchronized (bufferQueue) { while (!bufferQueue.isEmpty()) bufferQueue.get();// if (!bufferQueueEnabled)// { // // now that we not reading, stop queuing.// bufferQueueEnabled = false;// } } } catch (CaptureException e) { logger.log(Level.WARNING, "" + e, e); throw new IOException("" + e); } catch (InterruptedException e) { throw new InterruptedIOException("" + e); } finally { started.setValue(false); } } //@Override public Time getDuration() { return DURATION_UNBOUNDED; } public PushBufferStream[] getStreams() { if (TRACE) logger.fine("getStreams"); if (pushBufferStream == null) return new PushBufferStream[0]; return new PushBufferStream[] {pushBufferStream}; } private class MyCaptureObserver implements CaptureObserver { public void onError(CaptureStream sender, CaptureException e) { logger.log(Level.WARNING, "" + e, e); // TODO: how to handle? } private long firstImageTimestamp = -1L; // used to make timestamps start with zero // This is needed for proper playback when using JMF. private final FPSCounter fpsCounter = new FPSCounter(); public void onNewImage(CaptureStream sender, Image image) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -