capture.java
来自「This is processing for java examples.」· Java 代码 · 共 548 行 · 第 1/2 页
JAVA
548 行
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- *//* Part of the Processing project - http://processing.org Copyright (c) 2004-08 Ben Fry and Casey Reas The previous version of this code was developed by Hernando Barragan This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/package processing.video;import processing.core.*;import java.lang.reflect.*;import quicktime.*;import quicktime.qd.*;import quicktime.std.*;import quicktime.std.sg.*;import quicktime.util.RawEncodedImage;/** * Watchin' shit on the telly. */public class Capture extends PImage implements Runnable { // there are more, but these are all we'll provide for now // The useful ref page for <a href="http://developer.apple.com/documentation/Java/Reference/1.4.1/Java141API_QTJ/constant-values.html">quicktime constants</a> static public final int COMPOSITE = StdQTConstants.compositeIn; // 0 static public final int SVIDEO = StdQTConstants.sVideoIn; // 1 static public final int COMPONENT = StdQTConstants.rgbComponentIn; // 2 static public final int TUNER = StdQTConstants.tvTunerIn; // 6 static public final int NTSC = StdQTConstants.ntscIn; static public final int PAL = StdQTConstants.palIn; static public final int SECAM = StdQTConstants.secamIn; // no longer needed because parent field added to PImage //PApplet parent; Method captureEventMethod; String name; // keep track for error messages (unused) Thread runner; boolean available = false; /** Temporary storage for the raw image data read directly from the capture device */ public int data[]; public int dataWidth; public int dataHeight; public int dataRowBytes; /** True if this image is currently being cropped */ public boolean crop; public int cropX; public int cropY; public int cropW; public int cropH; public int frameRate; public RawEncodedImage raw; public SequenceGrabber capture; /** the guy who's doing all the work */ public SGVideoChannel channel; /** boundary of image at the requested size */ protected QDRect qdrect; /* static { try { QTSession.open(); } catch (QTException e) { e.printStackTrace(); } // this doesn't appear to do jack QTRuntimeException.registerHandler(new QTRuntimeHandler() { public void exceptionOccurred(QTRuntimeException e, Object obj, String s, boolean flag) { System.err.println("Problem inside Capture"); e.printStackTrace(); } }); } */ public Capture(PApplet parent, int requestWidth, int requestHeight) { this(parent, requestWidth, requestHeight, null, 30); } public Capture(PApplet parent, int reqWidth, int reqHeight, int frameRate) { this(parent, reqWidth, reqHeight, null, frameRate); } public Capture(PApplet parent, int reqWidth, int reqHeight, String name) { this(parent, reqWidth, reqHeight, name, 30); } /** * If 'name' is null or the empty string, it won't set a specific * device, which means that QuickTime will use that last device * used by a QuickTime application. * <P/> * Unfortunately, Apple's QuickTime API uses the name to select devices, * and in some cases there might be cameras with the same name on a machine. * If you ask for a camera of the same name in sequence, you might see if it * just does the right thing and grabs each separate camera in succession. * If that doesn't work, you might try calling settings() which will * bring up the prompt where you can select a capture device. * <P/> * If the following function: * <PRE>public void captureEvent(Capture c)</PRE> * is defined in the host PApplet, then it will be called every * time a new frame is available from the capture device. */ public Capture(final PApplet parent, final int requestWidth, final int requestHeight, final String name, final int frameRate) { // Running on EDT because of weird hang on OS X // http://dev.processing.org/bugs/show_bug.cgi?id=882 // QTSession.open() is hanging, not sure why, but it seems to prefer // being run from the EDT. Not sure if that's a mistaken expectation in // QTJava (we hadn't had trouble in the past because we did everything // on the EDT) or if something broken in more recent QTJ. Or (maybe most // likely) we're simply hitting some other threading strangeness, and // using invokeLater() isolates us from that. Which is a nice way of // saying that it's a hack. //SwingUtilities.invokeLater(new Runnable() { // public void run() { init(parent, requestWidth, requestHeight, name, frameRate); //} //}); } public void init(PApplet parent, int requestWidth, int requestHeight, String name, int frameRate) { this.parent = parent; this.name = name; this.frameRate = frameRate; try { QTSession.open(); } catch (QTException e) { e.printStackTrace(System.out); return; } try { qdrect = new QDRect(requestWidth, requestHeight); // workaround for bug with the intel macs QDGraphics qdgraphics = null; //new QDGraphics(qdrect); if (quicktime.util.EndianOrder.isNativeLittleEndian()) { qdgraphics = new QDGraphics(QDConstants.k32BGRAPixelFormat, qdrect); } else { qdgraphics = new QDGraphics(QDGraphics.kDefaultPixelFormat, qdrect); } capture = new SequenceGrabber(); capture.setGWorld(qdgraphics, null); channel = new SGVideoChannel(capture); channel.setBounds(qdrect); channel.setUsage(2); // what is this usage number? capture.startPreview(); // maybe this comes later? PixMap pixmap = qdgraphics.getPixMap(); raw = pixmap.getPixelData(); /* if (name == null) { channel.settingsDialog(); } else if (name.length() > 0) { channel.setDevice(name); } */ if ((name != null) && (name.length() > 0)) { channel.setDevice(name); } dataRowBytes = raw.getRowBytes(); dataWidth = dataRowBytes / 4; dataHeight = raw.getSize() / dataRowBytes; if (dataWidth != requestWidth) { crop = true; cropX = 0; cropY = 0; cropW = requestWidth; cropH = requestHeight; } // initialize my PImage self super.init(requestWidth, requestHeight, RGB); parent.registerDispose(this); try { captureEventMethod = parent.getClass().getMethod("captureEvent", new Class[] { Capture.class }); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } runner = new Thread(this); runner.start(); } catch (QTException qte) { //} catch (StdQTException qte) { //qte.printStackTrace(); int errorCode = qte.errorCode(); if (errorCode == Errors.couldntGetRequiredComponent) { // this can happen when the capture device isn't available // or wasn't shut down properly parent.die("No capture could be found, " + "or the VDIG is not installed correctly.", qte); } else { parent.die("Error while setting up Capture", qte); } } catch (Exception e) { parent.die("Error while setting up Capture", e); } } /** * True if a frame is ready to be read. * <PRE> * // put this somewhere inside draw * if (capture.available()) capture.read(); * </PRE> * Alternatively, you can use captureEvent(Capture c) to notify you * whenever available() is set to true. In which case, things might * look like this: * <PRE> * public void captureEvent(Capture c) { * c.read(); * // do something exciting now that c has been updated * } * </PRE> */ public boolean available() { return available; } /** * Set the video to crop from its original. * <P> * It seems common that captures add lines to the top or bottom
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?