How to take a screenshot of desktop fast with Java in Windows (ffmpeg, etc.)?(如何在Windows(ffmpeg等)中使用Java快速截取桌面截图?)
问题描述
我想使用 java 使用 FFMPEG 或其他解决方案截取我的机器的屏幕截图.我知道 linux 可以在没有 JNI 的情况下使用 ffmpeg,但是在 Windows 中运行它不起作用并且可能需要(JNI?)是否有一些简单的 Java 类的示例(以及其他任何必要的)来捕获可在 Windows 环境中运行的屏幕截图?FFMPEG 有什么替代品吗?我想以比 Java Robot API 更快的速度截屏,我发现它可以截屏,但比我想要的慢.
I would like to use java to take a screenshot of my machine using FFMPEG or some other solution. I know linux works with ffmpeg without JNI, but running it in Windows does not work and may require (JNI?) is there any sample of some simple Java class (and anything else necessary) to capture a screenshot runnable in a windows environment? Is there some alternative to FFMPEG? I want to take screenshot at a rate faster than the Java Robot API, which I have found to work at taking screenshots, but is slower than I would like.
我知道这在 Linux 中运行得非常快:
I know in Linux this works very fast:
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();
}
这在 windows 环境下不起作用.不确定是否有某种方法可以使用相同的代码,但使用 javacpp 使其实际工作而无需更改上述大部分代码.
This does not work in windows environment. Am not sure if there is some way I could use this same code, but use javacpp to actually get it working without having to change much of the above code.
目标是快速截取屏幕截图,但在截取不同"的截图后停止,也就是.屏幕因某些事件而改变,例如窗口关闭等.
Goal is to take screenshots of screen fast, but then stop after it takes a screenshot that is "different", aka. screen changed because of some event like, a window is window closed, etc.
推荐答案
使用内置 Robots 类比其他 Java 库更容易,应该可以满足您的需求.
Using the built-in Robots class is way easier than other Java libraries and should probably fit your needs.
如果您需要 >= 30fps(每秒超过 30 个屏幕截图)的流畅视频,您应该首先尝试使用 Robots 方法以及使用屏幕截图的异步存储来改进性能.
If you need a smooth video with >= 30fps (more than 30 screenshots per second), you should first try the Robots approach plus performance improvements there using asynchronous storing of the screenshots.
如果它不适合您,请尝试使用 JNA,这几乎可以保证(尽管它更复杂)可以实现流畅的屏幕捕获.
If it doesn't work for you, try using JNA and that is (even though it's more complex) almost guaranteed to work for smooth screen capturing.
robots 类确实可以做你想做的事,大多数使用 Robots 的屏幕捕获方法的问题是屏幕截图的保存.一种方法可能如下所示:循环 captureScreen() 方法,将屏幕抓取到 BufferedImage 中,将其转换为字节数组,并在将图像的未来引用添加到ArrayList 能够在存储图像数据的同时继续运行.
The robots class is indeed capable of doing what you want, the problem most screen capturing approaches with Robots have is the saving of the screenshots. An approach could look like that: Looping over the captureScreen() method, grabbing the screen into a BufferedImage, convert it to a byte array and save it with an asynchronous file writer to a target file after adding the future reference of your image to the ArrayList to be able to keep going while storing the image data.
// 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
}
JNA 方法
原问题:如何在 Java 中快速截屏?
由于链接是不好的做法,我将在此处发布示例:
As it is bad practice to just link, I will post the example here:
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();
}
更多信息和方法
使用时提高截屏速度Java 和 awt.Robot
http://www.dreamincode.net/论坛/主题/234896-faster-screen-capture/
如何在屏幕捕获程序中使用 Java 获得超过 30FPS?
http://ffmpeg.org
另请参阅
http://www.thepcwizard.in/2012/12/java-screen-capturing-tutorial.html
如何将屏幕截图开发为视频应用程序一个>
http://www.javalobby.org/forums/thread.jspa?threadID=16400&tstart=0
http:///hiddensciencex.blogspot.co.at/2014/01/fast-screen-capture-in-java-example.html
http://www.coderanch.com/t/340180/GUI/java/efficient-screenshot-Java
http://www.javaworld.com/article/2071755/learn-java/capture-the-screen.html
ffmpeg 用于截屏?
Java 小程序截屏到视频
使用 Java 截屏 DirectX 程序
这篇关于如何在Windows(ffmpeg等)中使用Java快速截取桌面截图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在Windows(ffmpeg等)中使用Java快速截取桌面截图?
基础教程推荐
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- 在螺旋中写一个字符串 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01