OSDN Git Service

[TAG]2.4.1
[nyartoolkit-and/nyartoolkit-and.git] / tags / 2.4.1 / src.utils / qt / jp / nyatla / nyartoolkit / qt / utils / QtCameraCapture.java
1 /* \r
2  * PROJECT: NyARToolkit Quicktime utilities.\r
3  * --------------------------------------------------------------------------------\r
4  * Copyright (C)2008 arc@dmz\r
5  *\r
6  * This program is free software; you can redistribute it and/or\r
7  * modify it under the terms of the GNU General Public License\r
8  * as published by the Free Software Foundation; either version 2\r
9  * of the License, or (at your option) any later version.\r
10  * \r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this framework; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  * \r
20  * For further information please contact.\r
21  *      \r
22  *      <arc(at)digitalmuseum.jp>\r
23  * \r
24  */\r
25 \r
26 package jp.nyatla.nyartoolkit.qt.utils;\r
27 \r
28 import java.awt.Dimension;\r
29 import java.awt.event.ActionEvent;\r
30 import java.awt.event.ActionListener;\r
31 import java.io.File;\r
32 \r
33 import javax.swing.Timer;\r
34 \r
35 import quicktime.QTException;\r
36 import quicktime.QTSession;\r
37 import quicktime.io.QTFile;\r
38 import quicktime.qd.PixMap;\r
39 import quicktime.qd.QDConstants;\r
40 import quicktime.qd.QDGraphics;\r
41 import quicktime.qd.QDRect;\r
42 import quicktime.std.StdQTConstants;\r
43 import quicktime.std.movies.Movie;\r
44 import quicktime.std.movies.media.DataRef;\r
45 import quicktime.std.sg.SGVideoChannel;\r
46 import quicktime.std.sg.SequenceGrabber;\r
47 import quicktime.util.RawEncodedImage;\r
48 \r
49 import jp.nyatla.nyartoolkit.NyARException;\r
50 \r
51 /**\r
52  * QuickTimeキャプチャクラス\r
53  *\r
54  */\r
55 public class QtCameraCapture implements ActionListener\r
56 {\r
57 \r
58         private Dimension image_size;\r
59 \r
60         private QtCaptureListener capture_listener;\r
61 \r
62         protected float fps = 30; // キャプチャ画像を取得するfps\r
63 \r
64         protected byte[] pixels; // キャプチャ画像の実データを保持するバイト型配列\r
65 \r
66         // キャプチャに使うタイマー\r
67         private Timer timer;\r
68 \r
69         // QTJava用のあれこれ\r
70         private QDGraphics graphics;\r
71 \r
72         private QDRect bounds;\r
73 \r
74         private SequenceGrabber grabber;\r
75 \r
76         private SGVideoChannel channel;\r
77 \r
78         private RawEncodedImage rawEncodedImage;\r
79 \r
80         private Movie movie;\r
81 \r
82         // ピクセルフォーマット変換用の一時変数\r
83         private int[] pixels_int;\r
84 \r
85         public static final int PIXEL_FORMAT_RGB = quicktime.util.EndianOrder.isNativeLittleEndian() ? QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat;\r
86 \r
87         public QtCameraCapture(int i_width, int i_height, float i_rate)\r
88         {\r
89                 image_size = new Dimension(i_width, i_height);\r
90                 fps = i_rate;\r
91         }\r
92 \r
93         public Dimension getSize()\r
94         {\r
95                 return image_size;\r
96         }\r
97 \r
98         public byte[] readBuffer() throws NyARException\r
99         {\r
100                 if (grabber == null) {\r
101                         throw new NyARException();\r
102                 }\r
103                 return pixels;\r
104         }\r
105 \r
106         public void setCaptureListener(QtCaptureListener i_listener) throws NyARException\r
107         {\r
108                 if (grabber != null) {\r
109                         throw new NyARException();\r
110                 }\r
111                 capture_listener = i_listener;\r
112 \r
113         }\r
114 \r
115         public void prepSetInput(Object input) throws QTException\r
116         {\r
117                 QTSession.open();\r
118                 bounds = new QDRect(image_size.width, image_size.height);\r
119                 graphics = new QDGraphics(quicktime.util.EndianOrder.isNativeLittleEndian() ? QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat, bounds);\r
120                 if (input != null && input.getClass().equals(File.class)) {\r
121                         movie = quicktime.std.movies.Movie.fromDataRef(new DataRef(new QTFile((File) input)), StdQTConstants.newMovieActive);\r
122                 } else {\r
123                         grabber = new SequenceGrabber();\r
124                         grabber.setGWorld(graphics, null);\r
125                         channel = new SGVideoChannel(grabber);\r
126                         channel.setBounds(bounds);\r
127 \r
128                         // seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…\r
129                         channel.setUsage(StdQTConstants.seqGrabPreview);\r
130 \r
131                         if (input != null) {\r
132                                 try {\r
133                                         channel.setDevice(input.toString());\r
134                                 } catch (QTException e) {\r
135                                         e.printStackTrace();\r
136                                         throw e;\r
137                                 }\r
138                         }\r
139                 }\r
140         }\r
141 \r
142         /**\r
143          * Webcamの設定ダイアログを表示する。\r
144          * 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。\r
145          */\r
146         public void prepShowDialog() throws QTException\r
147         {\r
148                 channel.settingsDialog();\r
149         }\r
150 \r
151         public void start() throws NyARException\r
152         {\r
153                 try {\r
154 \r
155                         if (grabber == null)\r
156                                 prepSetInput(null);\r
157 \r
158                         if (movie == null) {\r
159                                 grabber.prepare(true, false); // あってもなくてもよさそう\r
160                                 grabber.startPreview();\r
161                         } else {\r
162                                 movie.preroll(0, 1.0f);\r
163                                 while (movie.maxLoadedTimeInMovie() == 0)\r
164                                         movie.task(100);\r
165                                 movie.setRate(1);\r
166                                 movie.getPict(movie.getTime()).draw(graphics, bounds);\r
167                         }\r
168                         PixMap pixmap = graphics.getPixMap();\r
169                         rawEncodedImage = pixmap.getPixelData();\r
170 \r
171                         image_size.width = rawEncodedImage.getRowBytes() / 4;\r
172                         pixels = new byte[image_size.width * image_size.height * 3];\r
173                         pixels_int = new int[image_size.width * image_size.height];\r
174                 } catch (QTException e) {\r
175                         QTSession.close();\r
176                         throw new NyARException(e);\r
177                 }\r
178 \r
179                 // キャプチャイメージを定期的に更新するタイマー\r
180                 timer = new Timer((int) (1000 / fps), this);\r
181                 timer.start();\r
182         }\r
183 \r
184         public void stop()\r
185         {\r
186                 finalize();\r
187         }\r
188 \r
189         /** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */\r
190         public void actionPerformed(ActionEvent event)\r
191         {\r
192 \r
193                 // 画像をQTJavaのRawEncodedImageとして取得\r
194                 try {\r
195                         if (movie == null) {\r
196                                 grabber.idle();\r
197                         } else {\r
198                                 if (movie.isDone())\r
199                                         movie.goToBeginning();\r
200                                 movie.getPict(movie.getTime()).draw(graphics, bounds);\r
201                         }\r
202                 } catch (QTException e) {\r
203                         QTSession.close();\r
204                         e.printStackTrace();\r
205                 }\r
206 \r
207                 // RawEncodedImageをint列に落とし込む\r
208                 rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);\r
209 \r
210                 // バイト列を生成する\r
211                 int idx_byte = 0;\r
212                 for (int idx = 0; idx < image_size.width * image_size.height; idx++) {\r
213                         pixels[idx_byte++] = (byte) (pixels_int[idx] >> 16);\r
214                         pixels[idx_byte++] = (byte) (pixels_int[idx] >> 8 & 0xff);\r
215                         pixels[idx_byte++] = (byte) (pixels_int[idx] & 0xff);\r
216                 }\r
217 \r
218                 // 各リスナに更新されたバイト列を渡す\r
219                 capture_listener.onUpdateBuffer(pixels);\r
220         }\r
221 \r
222         protected void finalize()\r
223         {\r
224                 try {\r
225                         if (movie == null) {\r
226                                 grabber.stop();\r
227                                 grabber.release();\r
228                                 grabber.disposeChannel(channel);\r
229                         }\r
230                 } catch (Exception e) {\r
231                         e.printStackTrace();\r
232                 } finally {\r
233                         QTSession.close();\r
234                 }\r
235                 timer.stop();\r
236         }\r
237 \r
238 }\r