📄 qtcameracapture.java
字号:
/*
* PROJECT: NyARToolkit Quicktime utilities.
* --------------------------------------------------------------------------------
* Copyright (C)2008 arc@dmz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this framework; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For further information please contact.
*
* <arc(at)digitalmuseum.jp>
*
*/
package jp.nyatla.nyartoolkit.qt.utils;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.Timer;
import quicktime.QTException;
import quicktime.QTSession;
import quicktime.io.QTFile;
import quicktime.qd.PixMap;
import quicktime.qd.QDConstants;
import quicktime.qd.QDGraphics;
import quicktime.qd.QDRect;
import quicktime.std.StdQTConstants;
import quicktime.std.movies.Movie;
import quicktime.std.movies.media.DataRef;
import quicktime.std.sg.SGVideoChannel;
import quicktime.std.sg.SequenceGrabber;
import quicktime.util.RawEncodedImage;
import jp.nyatla.nyartoolkit.NyARException;
/**
* QuickTimeキャプチャクラス
*
*/
public class QtCameraCapture implements ActionListener
{
private Dimension image_size;
private QtCaptureListener capture_listener;
protected float fps = 30; // キャプチャ画像を取得するfps
protected byte[] pixels; // キャプチャ画像の実データを保持するバイト型配列
// キャプチャに使うタイマー
private Timer timer;
// QTJava用のあれこれ
private QDGraphics graphics;
private QDRect bounds;
private SequenceGrabber grabber;
private SGVideoChannel channel;
private RawEncodedImage rawEncodedImage;
private Movie movie;
// ピクセルフォーマット変換用の一時変数
private int[] pixels_int;
public static final int PIXEL_FORMAT_RGB = quicktime.util.EndianOrder.isNativeLittleEndian() ? QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat;
public QtCameraCapture(int i_width, int i_height, float i_rate)
{
image_size = new Dimension(i_width, i_height);
fps = i_rate;
}
public Dimension getSize()
{
return image_size;
}
public byte[] readBuffer() throws NyARException
{
if (grabber == null) {
throw new NyARException();
}
return pixels;
}
public void setCaptureListener(QtCaptureListener i_listener) throws NyARException
{
if (grabber != null) {
throw new NyARException();
}
capture_listener = i_listener;
}
public void prepSetInput(Object input) throws QTException
{
QTSession.open();
bounds = new QDRect(image_size.width, image_size.height);
graphics = new QDGraphics(quicktime.util.EndianOrder.isNativeLittleEndian() ? QDConstants.k32BGRAPixelFormat : QDGraphics.kDefaultPixelFormat, bounds);
if (input != null && input.getClass().equals(File.class)) {
movie = quicktime.std.movies.Movie.fromDataRef(new DataRef(new QTFile((File) input)), StdQTConstants.newMovieActive);
} else {
grabber = new SequenceGrabber();
grabber.setGWorld(graphics, null);
channel = new SGVideoChannel(grabber);
channel.setBounds(bounds);
// seqGrabPreview == 2, Processingでmagic numberとしてハードコートされていた…
channel.setUsage(StdQTConstants.seqGrabPreview);
if (input != null) {
try {
channel.setDevice(input.toString());
} catch (QTException e) {
e.printStackTrace();
throw e;
}
}
}
}
/**
* Webcamの設定ダイアログを表示する。
* 既定のWebcamでは駄目な場合(複数のWebcamが接続されているPCなど)ではこれを実行するとよい。
*/
public void prepShowDialog() throws QTException
{
channel.settingsDialog();
}
public void start() throws NyARException
{
try {
if (grabber == null)
prepSetInput(null);
if (movie == null) {
grabber.prepare(true, false); // あってもなくてもよさそう
grabber.startPreview();
} else {
movie.preroll(0, 1.0f);
while (movie.maxLoadedTimeInMovie() == 0)
movie.task(100);
movie.setRate(1);
movie.getPict(movie.getTime()).draw(graphics, bounds);
}
PixMap pixmap = graphics.getPixMap();
rawEncodedImage = pixmap.getPixelData();
image_size.width = rawEncodedImage.getRowBytes() / 4;
pixels = new byte[image_size.width * image_size.height * 3];
pixels_int = new int[image_size.width * image_size.height];
} catch (QTException e) {
QTSession.close();
throw new NyARException(e);
}
// キャプチャイメージを定期的に更新するタイマー
timer = new Timer((int) (1000 / fps), this);
timer.start();
}
public void stop()
{
finalize();
}
/** タイマー処理。キャプチャイメージの更新結果をリスナに伝える。 */
public void actionPerformed(ActionEvent event)
{
// 画像をQTJavaのRawEncodedImageとして取得
try {
if (movie == null) {
grabber.idle();
} else {
if (movie.isDone())
movie.goToBeginning();
movie.getPict(movie.getTime()).draw(graphics, bounds);
}
} catch (QTException e) {
QTSession.close();
e.printStackTrace();
}
// RawEncodedImageをint列に落とし込む
rawEncodedImage.copyToArray(0, pixels_int, 0, pixels_int.length);
// バイト列を生成する
int idx_byte = 0;
for (int idx = 0; idx < image_size.width * image_size.height; idx++) {
pixels[idx_byte++] = (byte) (pixels_int[idx] >> 16);
pixels[idx_byte++] = (byte) (pixels_int[idx] >> 8 & 0xff);
pixels[idx_byte++] = (byte) (pixels_int[idx] & 0xff);
}
// 各リスナに更新されたバイト列を渡す
capture_listener.onUpdateBuffer(pixels);
}
protected void finalize()
{
try {
if (movie == null) {
grabber.stop();
grabber.release();
grabber.disposeChannel(channel);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
QTSession.close();
}
timer.stop();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -