2 * QuickTimeお手軽キャプチャクラス
\r
3 * (c)2008 arc@dmz, A虎@nyatla.jp
\r
4 * arc@digitalmuseum.jp
\r
7 package jp.nyatla.nyartoolkit.qt.utils;
\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
14 import javax.swing.Timer;
\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
30 import jp.nyatla.nyartoolkit.NyARException;
\r
33 public class QtCameraCapture implements ActionListener
\r
36 private Dimension image_size;
\r
37 private QtCaptureListener capture_listener;
\r
39 protected float fps = 30; // キャプチャ画像を取得するfps
\r
40 protected byte[] pixels; // キャプチャ画像の実データを保持するバイト型配列
\r
43 private Timer timer;
\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
53 // ピクセルフォーマット変換用の一時変数
\r
54 private int[] pixels_int;
\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
60 image_size = new Dimension(i_width,i_height);
\r
63 public Dimension getSize()
\r
67 public byte[] readBuffer() throws NyARException
\r
70 throw new NyARException();
\r
74 public void setCaptureListener(QtCaptureListener i_listener) throws NyARException
\r
77 throw new NyARException();
\r
79 capture_listener=i_listener;
\r
83 public void prepSetInput(Object input) throws QTException {
\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
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
96 grabber = new SequenceGrabber();
\r
97 grabber.setGWorld(graphics, null);
\r
98 channel = new SGVideoChannel(grabber);
\r
99 channel.setBounds(bounds);
\r
101 // seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…
\r
102 channel.setUsage(StdQTConstants.seqGrabPreview);
\r
104 if (input != null) {
\r
106 channel.setDevice(input.toString());
\r
107 } catch (QTException e) {
\r
108 e.printStackTrace();
\r
116 * Webcamの設定ダイアログを表示する。
\r
117 * 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。
\r
119 public void prepShowDialog() throws QTException { channel.settingsDialog(); }
\r
121 public void start() throws NyARException
\r
125 if (grabber == null) prepSetInput(null);
\r
127 if (movie == null) {
\r
128 grabber.prepare(true, false); // あってもなくてもよさそう
\r
129 grabber.startPreview();
\r
131 movie.preroll(0, 1.0f);
\r
132 while (movie.maxLoadedTimeInMovie() == 0)
\r
135 movie.getPict(movie.getTime()).draw(graphics, bounds);
\r
137 PixMap pixmap = graphics.getPixMap();
\r
138 rawEncodedImage = pixmap.getPixelData();
\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
145 throw new NyARException(e);
\r
148 // キャプチャイメージを定期的に更新するタイマー
\r
149 timer = new Timer((int) (1000/fps), this);
\r
157 /** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */
\r
158 public void actionPerformed(ActionEvent event) {
\r
160 // 画像をQTJavaのRawEncodedImageとして取得
\r
162 if (movie == null) {
\r
165 if (movie.isDone()) movie.goToBeginning();
\r
166 movie.getPict(movie.getTime()).draw(graphics, bounds);
\r
168 } catch (QTException e) {
\r
170 e.printStackTrace();
\r
173 // RawEncodedImageをint列に落とし込む
\r
174 rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);
\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
184 // 各リスナに更新されたバイト列を渡す
\r
185 capture_listener.onUpdateBuffer(pixels);
\r
188 protected void finalize()
\r
191 if (movie == null) {
\r
194 grabber.disposeChannel(channel);
\r
196 } catch (Exception e) {
\r
197 e.printStackTrace();
\r