Alternativa mais rápida para java.awt.Robot.createScreenCapture?

Eu estou fazendo um programa que requer pelo menos 24 screenshots por segundo para ser capturado. Atualmente, com o código abaixo, recebo apenas 1 por cada ~ 94 milissegundos, portanto, cerca de 10 por segundo.

Eu prefiro não usar nenhuma biblioteca de terceiros porque estou tentando mantê-la o menor possível, mas se eu conseguir um aumento significativo no desempenho, eu estarei disposto a fazê-lo. Também estou tentando manter essa plataforma independente, mas, novamente, se for um aumento de desempenho realmente significativo, estarei disposto a mantê-la limitada ao Windows.

edit: Eu já tentei de duas formas diferentes também; usando um trecho encontrado no site oracles e o apontado nos comentários abaixo. Todos os três levaram aproximadamente o mesmo tempo, 2,1-2,2 milhões de nanossegundos, o que é bastante ineficiente.

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); } } 

A única maneira de fazer isso será através do JNI ou possivelmente do JNA. Fiz algumas APIs de captura de canvas nativa e de benchmarking e consegui sustentar cerca de 45 FPS contra os robôs 8 FPS. Eu poderia estar começando em um projeto JNI para resolver este problema no futuro próximo. Eu atualizarei esta postagem com o URL do projeto, se isso for adiante.

No momento, criei um exemplo prático de uso do VLCJ e, em seguida, do DirectMediaPlayer ( https://github.com/caprica/vlcj/blob/master/src/test/java/uk/co/caprica/vlcj/test/ direct / DirectTestPlayer.java ) para obter o BufferedImage.

O JFrame não é necessário para funcionar corretamente.

Eu sei que esta é uma pergunta antiga, mas isso ainda é um problema hoje, então eu pensei em compartilhar.

VLCJ são ligações Java para LibVLC.

Exemplo de código:

  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); } }