OSDN Git Service

[バックアップ]nyartoolkit
[nyartoolkit-and/nyartoolkit-and.git] / trunk / src.utils / qt / jp / nyatla / nyartoolkit / qt / utils / QtCameraCapture.java
1 /**\r
2  * QuickTimeお手軽キャプチャクラス\r
3  * (c)2008 arc@dmz, A虎@nyatla.jp\r
4  * arc@digitalmuseum.jp\r
5  * http://nyatla.jp/\r
6  */\r
7 package jp.nyatla.nyartoolkit.qt.utils;\r
8 \r
9 import java.awt.Dimension;\r
10 import java.awt.event.ActionEvent;\r
11 import java.awt.event.ActionListener;\r
12 import java.io.File;\r
13 \r
14 import javax.swing.Timer;\r
15 \r
16 import quicktime.QTException;\r
17 import quicktime.QTSession;\r
18 import quicktime.io.QTFile;\r
19 import quicktime.qd.PixMap;\r
20 import quicktime.qd.QDConstants;\r
21 import quicktime.qd.QDGraphics;\r
22 import quicktime.qd.QDRect;\r
23 import quicktime.std.StdQTConstants;\r
24 import quicktime.std.movies.Movie;\r
25 import quicktime.std.movies.media.DataRef;\r
26 import quicktime.std.sg.SGVideoChannel;\r
27 import quicktime.std.sg.SequenceGrabber;\r
28 import quicktime.util.RawEncodedImage;\r
29 \r
30 import jp.nyatla.nyartoolkit.NyARException;\r
31 \r
32 \r
33 public class QtCameraCapture implements ActionListener\r
34 {\r
35 \r
36         private Dimension image_size;\r
37     private QtCaptureListener capture_listener;\r
38 \r
39         protected float fps = 30;                               // キャプチャ画像を取得するfps\r
40         protected byte[] pixels;                                // キャプチャ画像の実データを保持するバイト型配列\r
41 \r
42         // キャプチャに使うタイマー\r
43         private Timer timer;\r
44 \r
45         // QTJava用のあれこれ\r
46         private QDGraphics graphics;\r
47         private QDRect bounds;\r
48         private SequenceGrabber grabber;\r
49         private SGVideoChannel channel;\r
50         private RawEncodedImage rawEncodedImage;\r
51         private Movie movie;\r
52 \r
53         // ピクセルフォーマット変換用の一時変数\r
54         private int[] pixels_int;\r
55     \r
56     public static final int PIXEL_FORMAT_RGB = quicktime.util.EndianOrder.isNativeLittleEndian() ?\r
57                         QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat;\r
58     public QtCameraCapture(int i_width,int i_height,float i_rate)\r
59     {\r
60         image_size = new Dimension(i_width,i_height);\r
61         fps = i_rate;\r
62     }\r
63     public Dimension getSize()\r
64     {\r
65         return image_size;\r
66     }\r
67     public byte[] readBuffer() throws NyARException\r
68     {\r
69         if(grabber==null){\r
70             throw new NyARException();\r
71         }\r
72         return pixels;\r
73     }\r
74     public void setCaptureListener(QtCaptureListener i_listener) throws NyARException\r
75     {\r
76         if(grabber!=null){\r
77             throw new NyARException();\r
78         }\r
79         capture_listener=i_listener;\r
80         \r
81     }\r
82 \r
83     public void prepSetInput(Object input) throws QTException {\r
84                 QTSession.open();\r
85                 bounds = new QDRect(image_size.width, image_size.height);\r
86                 graphics = new QDGraphics(\r
87                                 quicktime.util.EndianOrder.isNativeLittleEndian() ?\r
88                                                 QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat,\r
89                                 bounds);\r
90                 if (input != null && input.getClass().equals(File.class)) {\r
91                         movie = quicktime.std.movies.Movie.fromDataRef(\r
92                                 new DataRef(new QTFile((File) input)),\r
93                                 StdQTConstants.newMovieActive\r
94                         );\r
95                 } else {\r
96                         grabber = new SequenceGrabber();\r
97                         grabber.setGWorld(graphics, null);\r
98                         channel = new SGVideoChannel(grabber);\r
99                         channel.setBounds(bounds);\r
100 \r
101                         // seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…\r
102                         channel.setUsage(StdQTConstants.seqGrabPreview);\r
103 \r
104                         if (input != null) {\r
105                                 try {\r
106                                         channel.setDevice(input.toString());\r
107                                 } catch (QTException e) {\r
108                                         e.printStackTrace();\r
109                                         throw e;\r
110                                 }\r
111                         }\r
112                 }\r
113         }\r
114 \r
115         /**\r
116          * Webcamの設定ダイアログを表示する。\r
117          * 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。\r
118          */\r
119         public void prepShowDialog() throws QTException { channel.settingsDialog(); }\r
120 \r
121     public void start() throws NyARException\r
122     {\r
123                 try {\r
124 \r
125                         if (grabber == null) prepSetInput(null);\r
126 \r
127                         if (movie == null) {\r
128                                 grabber.prepare(true, false); // あってもなくてもよさそう\r
129                                 grabber.startPreview();\r
130                         } else {\r
131                                 movie.preroll(0, 1.0f);\r
132                                 while (movie.maxLoadedTimeInMovie() == 0)\r
133                                         movie.task(100);\r
134                                 movie.setRate(1);\r
135                                 movie.getPict(movie.getTime()).draw(graphics, bounds);\r
136                         }\r
137                         PixMap pixmap = graphics.getPixMap();\r
138                         rawEncodedImage = pixmap.getPixelData();\r
139 \r
140                         image_size.width = rawEncodedImage.getRowBytes() / 4;\r
141                         pixels = new byte[image_size.width * image_size.height * 3];\r
142                         pixels_int = new int[image_size.width * image_size.height];\r
143                 } catch (QTException e) {\r
144                         QTSession.close();\r
145                         throw new NyARException(e);\r
146                 }\r
147 \r
148                 // キャプチャイメージを定期的に更新するタイマー\r
149                 timer = new Timer((int) (1000/fps), this);\r
150                 timer.start();\r
151     }\r
152     public void stop()\r
153     {\r
154         finalize();\r
155     }\r
156 \r
157         /** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */\r
158         public void actionPerformed(ActionEvent event) {\r
159 \r
160                 // 画像をQTJavaのRawEncodedImageとして取得\r
161                 try {\r
162                         if (movie == null) {\r
163                                 grabber.idle();\r
164                         } else {\r
165                                 if (movie.isDone()) movie.goToBeginning();\r
166                                 movie.getPict(movie.getTime()).draw(graphics, bounds);\r
167                         }\r
168                 } catch (QTException e) {\r
169                         QTSession.close();\r
170                         e.printStackTrace();\r
171                 }\r
172 \r
173                 // RawEncodedImageをint列に落とし込む\r
174                 rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);\r
175 \r
176                 // バイト列を生成する\r
177                 int idx_byte = 0;\r
178                 for (int idx = 0; idx < image_size.width*image_size.height; idx ++) {\r
179                         pixels[idx_byte ++] = (byte) (pixels_int[idx] >> 16);\r
180                         pixels[idx_byte ++] = (byte) (pixels_int[idx] >> 8 & 0xff);\r
181                         pixels[idx_byte ++] = (byte) (pixels_int[idx] & 0xff);\r
182                 }\r
183 \r
184                 // 各リスナに更新されたバイト列を渡す\r
185                 capture_listener.onUpdateBuffer(pixels);\r
186         }\r
187 \r
188     protected void finalize()\r
189     {\r
190                 try {\r
191                         if (movie == null) {\r
192                                 grabber.stop();\r
193                                 grabber.release();\r
194                                 grabber.disposeChannel(channel);\r
195                         }\r
196                 } catch (Exception e) {\r
197                         e.printStackTrace();\r
198                 } finally {\r
199                         QTSession.close();\r
200                 }\r
201                 timer.stop();\r
202     }\r
203 \r
204 }\r