как быстро сделать скриншот рабочего стола с помощью java в windows (ffmpeg и т. д.)?

<p>я хотел бы использовать java, чтобы сделать снимок экрана моей машины с помощью ffmpeg или другого решения. я знаю, что linux работает с ffmpeg без jni, но его запуск в windows не работает и может потребовать (jni?), есть ли какой-нибудь пример некоторого простого класса java (и всего остального необходимого) для захвата снимка экрана, который можно запустить в среде windows? есть ли какая-нибудь альтернатива ffmpeg? я хочу делать снимки экрана быстрее, чем api-интерфейс робота java, который, как мне показалось, работает при создании снимков экрана, но работает медленнее, чем хотелось бы.</p><p>я знаю, что в linux это работает очень быстро:</p><pre><code>import com.googlecode.javacv.*; public class screengrabber { public static void main(string[] args) throws exception { int x = 0, y = 0, w = 1024, h = 768; ffmpegframegrabber grabber = new ffmpegframegrabber(":0.0+" + x + "," + y); grabber.setformat("x11grab"); grabber.setimagewidth(w); grabber.setimageheight(h); grabber.start(); canvasframe frame = new canvasframe("screen capture"); while (frame.isvisible()) { frame.showimage(grabber.grab()); } frame.dispose(); grabber.stop(); } </code></pre><p>это не работает в среде windows. я не уверен, есть ли какой-нибудь способ, которым я мог бы использовать этот же код, но используйте javacpp, чтобы фактически заставить его работать без необходимости изменять большую часть приведенного выше кода.</p><p>цель состоит в том, чтобы быстро сделать скриншоты экрана, но затем остановиться после того, как он сделает снимок, который "другой", иначе. экран изменился из-за какого-либо события, например, окно закрыто и т. д.</p>

<p>использование встроенного <strong> класса robots </strong> намного проще, чем другие библиотеки java, и, вероятно, должно соответствовать вашим потребностям.</p><p>если вам нужно плавное видео с> = 30 кадров в секунду (более 30 снимков экрана в секунду), вам следует сначала попробовать подход "роботы" плюс улучшения производительности, используя асинхронное сохранение <strong> снимков экрана </strong>.</p><p>если это не работает для вас, попробуйте использовать <strong>jna</strong>, и это (хотя и более сложно) почти гарантированно будет работать для плавного захвата экрана.</p><h2>подход с роботами</h2><p>класс роботов действительно способен делать то, что вы хотите, проблема, которую большинство подходов к захвату экрана с помощью роботов имеет <strong> сохранение </strong> снимков экрана. подход может выглядеть следующим образом: цикл по методу capturescreen (), захват экрана в bufferedimage, преобразование его в байтовый массив и сохранение его с помощью асинхронного средства записи файлов в целевой файл после добавления будущей ссылки вашего изображения в arraylist, чтобы иметь возможность продолжать работу при сохранении данных изображения.</p><pre class="lang-none prettyprint-override"><code>// pseudo code while (capturing) { grab bufferedimage (screencapture) from screen convert bufferimage to byte array start asynchronous file channel to write to the output file and add the future reference (return value) to the arraylist } </code></pre><h2>подход с jna</h2><p>оригинальный вопрос: <a href="https://stackoverflow.com/questions/2912007/java-how-to-take-a-screenshot-fast">как быстро делать скриншоты на java?</a> </p><p>так как просто ссылаться, плохой практикой я опубликую пример здесь:</p><pre><code>import java.awt.rectangle; import java.awt.image.bufferedimage; import java.awt.image.colormodel; import java.awt.image.databuffer; import java.awt.image.databufferint; import java.awt.image.databufferushort; import java.awt.image.directcolormodel; import java.awt.image.raster; import java.awt.image.writableraster; import com.sun.jna.native; import com.sun.jna.platform.win32.w32api; import com.sun.jna.win32.w32apioptions; public class jnascreenshot { public static bufferedimage getscreenshot(rectangle bounds) { w32api.hdc windowdc = gdi.getdc(user.getdesktopwindow()); w32api.hbitmap outputbitmap = gdi.createcompatiblebitmap(windowdc, bounds.width, bounds.height); try { w32api.hdc blitdc = gdi.createcompatibledc(windowdc); try { w32api.handle oldbitmap = gdi.selectobject(blitdc, outputbitmap); try { gdi.bitblt(blitdc, 0, 0, bounds.width, bounds.height, windowdc, bounds.x, bounds.y, gdi32.srccopy); } finally { gdi.selectobject(blitdc, oldbitmap); } gdi32.bitmapinfo bi = new gdi32.bitmapinfo(40); bi.bmiheader.bisize = 40; boolean ok = gdi.getdibits(blitdc, outputbitmap, 0, bounds.height, (byte[]) null, bi, gdi32.dib\_rgb\_colors); if (ok) { gdi32.bitmapinfoheader bih = bi.bmiheader; bih.biheight = -math.abs(bih.biheight); bi.bmiheader.bicompression = 0; return bufferedimagefrombitmap(blitdc, outputbitmap, bi); } else { return null; } } finally { gdi.deleteobject(blitdc); } } finally { gdi.deleteobject(outputbitmap); } } private static bufferedimage bufferedimagefrombitmap(gdi32.hdc blitdc, gdi32.hbitmap outputbitmap, gdi32.bitmapinfo bi) { gdi32.bitmapinfoheader bih = bi.bmiheader; int height = math.abs(bih.biheight); final colormodel cm; final databuffer buffer; final writableraster raster; int stridebits = (bih.biwidth * bih.bibitcount); int stridebytesaligned = (((stridebits - 1) | 0x1f) + 1) >> 3; final int strideelementsaligned; switch (bih.bibitcount) { case 16: strideelementsaligned = stridebytesaligned / 2; cm = new directcolormodel(16, 0x7c00, 0x3e0, 0x1f); buffer = new databufferushort(strideelementsaligned * height); raster = raster.createpackedraster(buffer, bih.biwidth, height, strideelementsaligned, ((directcolormodel) cm).getmasks(), null); break; case 32: strideelementsaligned = stridebytesaligned / 4; cm = new directcolormodel(32, 0xff0000, 0xff00, 0xff); buffer = new databufferint(strideelementsaligned * height); raster = raster.createpackedraster(buffer, bih.biwidth, height, strideelementsaligned, ((directcolormodel) cm).getmasks(), null); break; default: throw new illegalargumentexception("unsupported bit count: " + bih.bibitcount); } final boolean ok; switch (buffer.getdatatype()) { case databuffer.type\_int: { int[] pixels = ((databufferint) buffer).getdata(); ok = gdi.getdibits(blitdc, outputbitmap, 0, raster.getheight(), pixels, bi, 0); } break; case databuffer.type\_ushort: { short[] pixels = ((databufferushort) buffer).getdata(); ok = gdi.getdibits(blitdc, outputbitmap, 0, raster.getheight(), pixels, bi, 0); } break; default: throw new assertionerror("unexpected buffer element type: " + buffer.getdatatype()); } if (ok) { return new bufferedimage(cm, raster, false, null); } else { return null; } } private static final user32 user = user32.instance; private static final gdi32 gdi = gdi32.instance; } interface gdi32 extends com.sun.jna.platform.win32.gdi32 { gdi32 instance = (gdi32) native.loadlibrary(gdi32.class); boolean bitblt(hdc hdcdest, int nxdest, int nydest, int nwidth, int nheight, hdc hdcsrc, int nxsrc, int nysrc, int dwrop); hdc getdc(hwnd hwnd); boolean getdibits(hdc dc, hbitmap bmp, int startscan, int scanlines, byte[] pixels, bitmapinfo bi, int usage); boolean getdibits(hdc dc, hbitmap bmp, int startscan, int scanlines, short[] pixels, bitmapinfo bi, int usage); boolean getdibits(hdc dc, hbitmap bmp, int startscan, int scanlines, int[] pixels, bitmapinfo bi, int usage); int srccopy = 0xcc0020; } interface user32 extends com.sun.jna.platform.win32.user32 { user32 instance = (user32) native.loadlibrary(user32.class, w32apioptions.unicode\_options); hwnd getdesktopwindow(); } </code></pre><h2>больше информации и подходов</h2><ul> <li> <p> <a href="https://stackoverflow.com/questions/19843050/increasing-screen-capture-speed-when-using-java-and-awt-robot">увеличение скорости захвата экрана при использовании java и awt.robot</a> </p> </li> <li> <p> <a href="http://www.dreamincode.net/forums/topic/234896-faster-screen-capture/">http://www.dreamincode.net/forums/topic/234896-faster-screen-capture/</a> </p> </li> <li> <p> <a href="https://stackoverflow.com/questions/13773870/how-to-get-over-30fps-using-java-in-a-screen-capture-program">как получить более 30fps, используя java в программе захвата экрана?</a> </p> </li> <li> <p> <a href="http://ffmpeg.org">http://ffmpeg.org</a> </p> </li> </ul><p><strong> смотрите также </strong></p><ul> <li> <p> <a href="http://www.thepcwizard.in/2012/12/java-screen-capturing-tutorial.html">http://www.thepcwizard.in/2012/12/java-screen-capturing-tutorial.html</a> </p> </li> <li> <p> <a href="https://stackoverflow.com/questions/6236119/how-to-develop-screen-capture-to-video-application">как разработать снимок экрана для видео приложения</a> </p> </li> <li> <p> <a href="http://www.javalobby.org/forums/thread.jspa?threadid=16400&tstart=0">http://www.javalobby.org/forums/thread.jspa?threadid=16400&tstart=</a> </p> </li> <li> <p> <a href="http://hiddensciencex.blogspot.co.at/2014/01/fast-screen-capture-in-java-example.html">http://hiddensciencex.blogspot.co.at/2014/01/fast-screen-capture-in-java-example.html</a> </p> </li> <li> <p> <a href="http://www.coderanch.com/t/340180/gui/java/efficient-screenshot-java">http://www.coderanch.com/t/340180/gui/java/efficient-screenshot-java</a> </p> </li> <li> <p> <a href="http://www.javaworld.com/article/2071755/learn-java/capture-the-screen.html">http://www.javaworld.com/article/2071755/learn-java/capture-the-screen.html</a> </p> </li> <li> <p> <a href="https://stackoverflow.com/questions/10180323/ffmpeg-for-screen-capture">ffmpeg для захвата экрана?</a> </p> </li> <li> <p> <a href="https://stackoverflow.com/questions/2059309/java-applet-screen-capture-to-a-video">захват экрана java-апплета в видео</a> </p> </li> <li> <p> <a href="https://stackoverflow.com/questions/6675693/screen-capture-of-directx-programs-with-java">снимок экрана программ directx с java</a> </p> </li> </ul>

<p>в соответствии с официальным <a href="https://trac.ffmpeg.org/wiki/capture/desktop">документация ffmpeg</a> вы сможете сохранить его довольно кроссплатформенным, если вы сделаете параметр <code>file</code>, передаваемый <code>ffmpegframegrabber</code> (который на самом деле является параметром <code>input</code>, который передается как опция <code>-i</code> для ffmpeg ) придерживайтесь <a href="http://ffmpeg.org/ffmpeg-devices.html">различные форматы, ожидаемые каждым <code>device</code></a> .</p><p>то есть:</p><p>для windows: <code>dshow</code> ожидает <code>-i video="screen-capture-recorder"</code></p><p>для osx: <code>avfoundation</code> ожидает <code>-i "<screen device index>":</code></p><p>и для linux: <code>x11grab</code> ожидает <code>-i :<display id>+<x>,<y></code>.</p><p>так что просто передав эти значения (аргументы <code>-i</code>) в конструктор и соответственно установив формат (через <code>setformat</code>), нужно добиться цели.</p>

<p>вам потребуется использовать jni или jna для вызова некоторой комбинации createcompatiblebitmap, xgetimage, directx или opengl, чтобы получить снимок экрана и затем скопировать некоторые необработанные растровые данные обратно в java. мое профилирование показало ускорение примерно на 400% по сравнению с классом robot при доступе к необработанным растровым данным в x11. в настоящее время я не тестировал другие платформы. некоторый очень ранний код доступен <a href="https://github.com/kwhat/libscreenshot">здесь</a> , но у меня не было много времени, чтобы поработать над ним в последнее время.</p>

<p>вы знакомы с xuggler? он использует ffmpeg для кодирования и декодирования. я узнал об этом несколько месяцев назад, когда мне пришлось извлекать кадры из видео, и оно работало без сбоев.</p><p>на официальном сайте вы можете найти несколько примеров, в том числе "capturescreentofile.java". для получения дополнительной информации перейдите по этим ссылкам:</p><p> <a href="http://www.xuggle.com/xuggler/">http://www.xuggle.com/xuggler/</a> </p><p> <a href="https://github.com/artclarke/xuggle-xuggler/tree/master/src/com/xuggle/xuggler/demos">https://github.com/artclarke/xuggle-xuggler/tree/master/src/com/xuggle/xuggler/demos</a> </p>