KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inzyme > jmds > DSSourceStream


1 package com.inzyme.jmds;
2
3 import java.io.IOException JavaDoc;
4
5 import javax.media.Buffer;
6 import javax.media.Format;
7 import javax.media.format.VideoFormat;
8 import javax.media.protocol.BufferTransferHandler;
9 import javax.media.protocol.ContentDescriptor;
10 import javax.media.protocol.PushBufferStream;
11 import javax.media.protocol.SourceStream;
12
13 import com.sun.media.vfw.BitMapInfo;
14
15 /**
16  * DSSourceStream provides an interface to the data stream from the
17  * DirectShow capture device.
18  *
19  * Note that must stop and disconnect this stream before closing your
20  * VM. There is a finalizer on this object, but if your VM process is
21  * killed, your capture card can be left in an unstable state. This
22  * can effectively turn this class into DSRebootYourComputerSourceStream.
23  *
24  * @author Mike Schrag
25  */

26 public class DSSourceStream implements PushBufferStream {
27     private DSCapturePin myCapturePin;
28
29     private CaptureRunnable myCaptureRunnable;
30     private Thread JavaDoc myCaptureThread;
31
32     private BufferTransferHandler myTransferHandler;
33     private boolean myConnected;
34     private boolean myStarted;
35     private boolean myStopRequested;
36
37     private Format myFormat;
38
39     private Object JavaDoc myRestartLock = new Object JavaDoc();
40     
41     /**
42      * Constructs a new DSSourceStream.
43      *
44      * @param _capturePin the capture pin to connect to
45      */

46     public DSSourceStream(DSCapturePin _capturePin) {
47         myCapturePin = _capturePin;
48         myCaptureRunnable = new CaptureRunnable();
49     }
50     
51     /**
52      * Returns the current format for this stream.
53      *
54      * @return the current format for this stream
55      */

56     public Format getFormat() {
57         BitMapInfo bmi = new BitMapInfo();
58         fillInBitMapInfo(bmi);
59         float frameRate = getFrameRate();
60         myFormat = bmi.createVideoFormat(Format.byteArray, frameRate);
61         return myFormat;
62     }
63     
64     /**
65      * Sets the format of this stream to the specified format index (as returned
66      * by this stream's DataSource's FilterControl.getSupportedFormats(). I haven't
67      * tried changing formats after the stream is started, so you're on your own
68      * there for now.
69      *
70      * @param _index the index of the format to set
71      */

72     public Format setFormat(int _index) {
73         setFormat0(_index);
74         return getFormat();
75     }
76     
77     /**
78      * Reads from the capture device into the specified buffer.
79      *
80      * @param _buffer the buffer to read into
81      */

82     public void read(Buffer _buffer) throws IOException JavaDoc {
83         Object JavaDoc data = _buffer.getData();
84         int length = ((VideoFormat) myFormat).getMaxDataLength();
85
86         if (data == null || !(data instanceof byte[]) || ((byte[]) data).length != length) {
87             data = new byte[length];
88             _buffer.setData(data);
89             _buffer.setLength(length);
90         }
91
92         int offset = _buffer.getOffset();
93         _buffer.setFormat(myFormat);
94
95         int pos = 0;
96         while (!myStopRequested && pos < length) {
97             pos += fillBuffer((byte[]) data, offset + pos, length - pos);
98         }
99
100         _buffer.setData(data);
101         _buffer.setOffset(offset);
102         _buffer.setLength(length);
103         _buffer.setTimeStamp(Buffer.TIME_UNKNOWN);
104     }
105
106     public void setTransferHandler(BufferTransferHandler _transferHandler) {
107         myTransferHandler = _transferHandler;
108     }
109
110     public ContentDescriptor getContentDescriptor() {
111         return new ContentDescriptor(ContentDescriptor.RAW);
112     }
113
114     public long getContentLength() {
115         return SourceStream.LENGTH_UNKNOWN;
116     }
117     
118     /**
119      * Always returns false.
120      */

121     public boolean endOfStream() {
122         return false;
123     }
124
125     /**
126      * Always returns null.
127      */

128     public Object JavaDoc getControl(String JavaDoc _controlClass) {
129         return null;
130     }
131     
132     /**
133      * Returns an empty array
134      */

135     public Object JavaDoc[] getControls() {
136         return new Object JavaDoc[0];
137     }
138     
139     /**
140      * Starts this stream. You must have connected to this stream prior to attempting
141      * to start it.
142      *
143      * This will create a capture thread that will poll your capture device, attempting to
144      * read frames off as quickly as possible and push them out onto the stream.
145      */

146     public void start() {
147         if (!myConnected) {
148             throw new IllegalStateException JavaDoc("You must connect to this stream prior to starting it.");
149         }
150         
151         // try { new BufferedReader(new InputStreamReader(System.in)).readLine(); } catch (Throwable t) { }
152
if (myStarted) {
153             return;
154         }
155         
156         // block on the restart lock in case there is a currently stopping
157
// or starting thread
158
synchronized (myRestartLock) {
159             myStarted = true;
160             myStopRequested = false;
161
162             myCaptureThread = new Thread JavaDoc(myCaptureRunnable, "Capture Thread");
163             myCaptureThread.start();
164
165             try {
166                 myRestartLock.wait();
167             }
168             catch (InterruptedException JavaDoc e) {
169                 e.printStackTrace();
170             }
171         }
172     }
173     
174     /**
175      * Request for this stream to stop. This is not a blocking call, but the stream
176      * will stop as quickly as it can (usually within a single frame).
177      */

178     public void stop() {
179         if (!myStarted) {
180             return;
181         }
182
183         myStopRequested = true;
184     }
185
186     protected void finalize() throws Throwable JavaDoc {
187         stop();
188         disconnect();
189     }
190
191     void connect() {
192         if (myConnected) {
193             return;
194         }
195         myConnected = true;
196         connect0();
197     }
198
199     void disconnect() {
200         if (!myConnected) {
201             return;
202         }
203         disconnect0();
204         myConnected = false;
205     }
206
207     private native void setFormat0(int _index);
208     
209     private native void fillInBitMapInfo(BitMapInfo _bitMapInfo);
210
211     private native float getFrameRate();
212
213     private native void connect0();
214
215     private native void start0();
216
217     private native void stop0();
218
219     private native void disconnect0();
220
221     private native int getBufferSize();
222
223     private native int fillBuffer(byte[] _buffer, int _offset, int _length);
224
225     private class CaptureRunnable implements Runnable JavaDoc {
226         public void run() {
227             start0();
228             
229             // notify sleepers that we're done starting up
230
synchronized (myRestartLock) {
231                 myRestartLock.notifyAll();
232             }
233             
234             // chill until there is data in the buffer
235
while (!myStopRequested && getBufferSize() == 0) {
236                 try {
237                     Thread.sleep(100);
238                 }
239                 catch (Throwable JavaDoc t) {
240                     t.printStackTrace();
241                 }
242             }
243             
244             // grab frames as fast as possible
245
while (!myStopRequested) {
246                 if (myTransferHandler != null) {
247                     myTransferHandler.transferData(DSSourceStream.this);
248                 }
249                 else {
250                     // if there's no transfer handler, just wait for a bit and try again
251
try {
252                         Thread.sleep(100);
253                     }
254                     catch (Throwable JavaDoc t) {
255                     }
256                 }
257                 
258                 // This sleep is here because there is the
259
// potential that you can starve your PC
260
// while polling the capture card for video.
261
try {
262                     Thread.sleep(20);
263                 }
264                 catch (Throwable JavaDoc t) {
265                 }
266             }
267
268             stop0();
269             
270             // notify waiters that we're done stopping the thread
271
synchronized (myRestartLock) {
272                 myStarted = false;
273                 myRestartLock.notify();
274             }
275         }
276     }
277 }
278
Popular Tags