2 * PROJECT: NyARToolkit Quicktime utilities.
\r
3 * --------------------------------------------------------------------------------
\r
4 * Copyright (C)2008 arc@dmz
\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
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
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
20 * For further information please contact.
\r
22 * <arc(at)digitalmuseum.jp>
\r
26 package jp.nyatla.nyartoolkit.qt.utils;
\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
33 import javax.swing.Timer;
\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
49 import jp.nyatla.nyartoolkit.NyARException;
\r
55 public class QtCameraCapture implements ActionListener
\r
58 private Dimension image_size;
\r
60 private QtCaptureListener capture_listener;
\r
62 protected float fps = 30; // キャプチャ画像を取得するfps
\r
64 protected byte[] pixels; // キャプチャ画像の実データを保持するバイト型配列
\r
67 private Timer timer;
\r
70 private QDGraphics graphics;
\r
72 private QDRect bounds;
\r
74 private SequenceGrabber grabber;
\r
76 private SGVideoChannel channel;
\r
78 private RawEncodedImage rawEncodedImage;
\r
80 private Movie movie;
\r
82 // ピクセルフォーマット変換用の一時変数
\r
83 private int[] pixels_int;
\r
85 public static final int PIXEL_FORMAT_RGB = quicktime.util.EndianOrder.isNativeLittleEndian() ? QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat;
\r
87 public QtCameraCapture(int i_width, int i_height, float i_rate)
\r
89 image_size = new Dimension(i_width, i_height);
\r
93 public Dimension getSize()
\r
98 public byte[] readBuffer() throws NyARException
\r
100 if (grabber == null) {
\r
101 throw new NyARException();
\r
106 public void setCaptureListener(QtCaptureListener i_listener) throws NyARException
\r
108 if (grabber != null) {
\r
109 throw new NyARException();
\r
111 capture_listener = i_listener;
\r
115 public void prepSetInput(Object input) throws QTException
\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
123 grabber = new SequenceGrabber();
\r
124 grabber.setGWorld(graphics, null);
\r
125 channel = new SGVideoChannel(grabber);
\r
126 channel.setBounds(bounds);
\r
128 // seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…
\r
129 channel.setUsage(StdQTConstants.seqGrabPreview);
\r
131 if (input != null) {
\r
133 channel.setDevice(input.toString());
\r
134 } catch (QTException e) {
\r
135 e.printStackTrace();
\r
143 * Webcamの設定ダイアログを表示する。
\r
144 * 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。
\r
146 public void prepShowDialog() throws QTException
\r
148 channel.settingsDialog();
\r
151 public void start() throws NyARException
\r
155 if (grabber == null)
\r
156 prepSetInput(null);
\r
158 if (movie == null) {
\r
159 grabber.prepare(true, false); // あってもなくてもよさそう
\r
160 grabber.startPreview();
\r
162 movie.preroll(0, 1.0f);
\r
163 while (movie.maxLoadedTimeInMovie() == 0)
\r
166 movie.getPict(movie.getTime()).draw(graphics, bounds);
\r
168 PixMap pixmap = graphics.getPixMap();
\r
169 rawEncodedImage = pixmap.getPixelData();
\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
176 throw new NyARException(e);
\r
179 // キャプチャイメージを定期的に更新するタイマー
\r
180 timer = new Timer((int) (1000 / fps), this);
\r
189 /** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */
\r
190 public void actionPerformed(ActionEvent event)
\r
193 // 画像をQTJavaのRawEncodedImageとして取得
\r
195 if (movie == null) {
\r
198 if (movie.isDone())
\r
199 movie.goToBeginning();
\r
200 movie.getPict(movie.getTime()).draw(graphics, bounds);
\r
202 } catch (QTException e) {
\r
204 e.printStackTrace();
\r
207 // RawEncodedImageをint列に落とし込む
\r
208 rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);
\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
218 // 各リスナに更新されたバイト列を渡す
\r
219 capture_listener.onUpdateBuffer(pixels);
\r
222 protected void finalize()
\r
225 if (movie == null) {
\r
228 grabber.disposeChannel(channel);
\r
230 } catch (Exception e) {
\r
231 e.printStackTrace();
\r