java.awt.Robot.createScreenCapture更快的替代方案?

我正在制作一个每秒至少需要截屏24张的程序。 目前使用下面的代码我每隔约94毫秒只得到1,所以每秒约10。

我不想使用任何第三方库,因为我试图尽可能地保持它,但如果我的性能显着提高,我愿意。 我也试图保持这个平台的独立性,但同样,如果它的性能提升非常显着,我愿意将它限制在Windows中。

编辑:我现在也尝试了两种不同的方式; 使用在oracles网站上找到的片段以及下面评论中指出的片段。 所有三个大约在同一时间,2.1-2.2百纳秒,这是非常低效的。

public abstract class Benchmark { private final int iterations; public Benchmark(int iterations) { this.iterations = iterations; } public abstract void logic(); public void start() { long start = System.nanoTime(); for (int iteration = 0; iteration < iterations; iteration++) { long iterationStart = System.nanoTime(); logic(); System.out.println("iteration: " + iteration + " took: " + (System.nanoTime() - iterationStart) + " nanoseconds."); } long total = (System.nanoTime() - start); System.out.println(iterations + " iterations took: " + total + " nanoseconds. Average iteration was: " + (total / iterations)); } } 

_

 import java.awt.AWTException; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; public class RobotBenchmark extends Benchmark { private final Robot robot; private final Rectangle screen; public static void main(String[] args) { Benchmark benchmark; try { benchmark = new RobotBenchmark(24); benchmark.start(); } catch (AWTException e) { e.printStackTrace(); } } public RobotBenchmark(int iterations) throws AWTException { super(iterations); robot = new Robot(); screen = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); } @Override public void logic() { robot.createScreenCapture(screen); } } 

_

 import java.awt.AWTException; import java.awt.GraphicsDevice; import java.awt.HeadlessException; import java.awt.Rectangle; public class DirectRobotBenchmark extends Benchmark { private final GraphicsDevice device; private final Rectangle screenRectangle; private final DirectRobot robot; private int[] screen; public static void main(String[] args) { Benchmark benchmark; try { benchmark = new DirectRobotBenchmark(24); benchmark.start(); } catch (HeadlessException | AWTException e) { e.printStackTrace(); } } public DirectRobotBenchmark(int iterations) throws HeadlessException, AWTException { super(iterations); device = DirectRobot.getDefaultScreenDevice(); screenRectangle = new Rectangle(1920, 1080); robot = new DirectRobot(device); screen = new int[screenRectangle.width * screenRectangle.height]; } @Override public void logic() { screen = robot.getRGBPixels(screenRectangle); } } 

_

 import java.awt.AWTException; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.peer.RobotPeer; import sun.awt.SunToolkit; @SuppressWarnings("restriction") public class RobotPeerBenchmark extends Benchmark { private final SunToolkit toolkit; private final RobotPeer peer; private final Rectangle screenRectangle; private int[] screen; public static void main(String[] args) { try { Benchmark robotPeerBenchmark = new RobotPeerBenchmark(24); robotPeerBenchmark.start(); } catch (AWTException e) { e.printStackTrace(); } } public RobotPeerBenchmark(int iterations) throws AWTException { super(iterations); toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); peer = toolkit.createRobot(new Robot(), GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()); screenRectangle = new Rectangle(toolkit.getScreenSize()); screen = new int[screenRectangle.width * screenRectangle.height]; } @Override public void logic() { screen = peer.getRGBPixels(screenRectangle); } } 

唯一的方法是通过JNI或JNA。 我做了一些基准测试和原生屏幕捕获API,它能够维持大约45 FPS与机器人8 FPS。 我可能会在JNI项目上开始在不久的将来解决这个问题。 如果继续,我会用项目URL更新这篇文章。

我目前已经建立了一个使用VLCJ然后使用DirectMediaPlayer的工作示例( https://github.com/caprica/vlcj/blob/master/src/test/java/uk/co/caprica/vlcj/test/ direct / DirectTestPlayer.java )获取BufferedImage。

JFrame不是正常工作所必需的。

我知道这是一个老问题,但今天仍然存在问题,所以我想我会分享。

VLCJ是LibVLC的Java绑定。

示例代码:

  private BufferedImage image; private MediaPlayerFactory factory; private DirectMediaPlayer mediaPlayer; public void start() { image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(width, height); image.setAccelerationPriority(1.0f); String mrl = "screen://"; String[] options = { ":screen-fps=30", ":live-caching=0", ":screen-width=1920", ":screen-height=1080", ":screen-left=0", ":screen-top=0" }; factory = new MediaPlayerFactory(); mediaPlayer = factory.newDirectMediaPlayer(new TestBufferFormatCallback(), new TestRenderCallback()); mediaPlayer.playMedia(mrl, options); } // Callbacks are required. private final class TestRenderCallback extends RenderCallbackAdapter { public TestRenderCallback() { super(((DataBufferInt) image.getRaster().getDataBuffer()).getData()); } @Override public void onDisplay(DirectMediaPlayer mediaPlayer, int[] data) { // The image data could be manipulated here... /* RGB to GRAYScale conversion example */ // for(int i=0; i < data.length; i++){ // int argb = data[i]; // int b = (argb & 0xFF); // int g = ((argb >> 8 ) & 0xFF); // int r = ((argb >> 16 ) & 0xFF); // int grey = (r + g + b + g) >> 2 ; //performance optimized - not real grey! // data[i] = (grey << 16) + (grey << 8) + grey; // } // imagePane.repaint(); } } private final class TestBufferFormatCallback implements BufferFormatCallback { @Override public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) { return new RV32BufferFormat(width, height); } }