加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

如何在Windows(ffmpeg等)中使用Java快速截取桌面?

发布时间:2020-12-13 20:43:58 所属栏目:Windows 来源:网络整理
导读:我想使用java来使用FFMPEG或其他解决方案截取我的机器的屏幕截图.我知道linux可以在没有JNI的情况下使用ffmpeg,但是在Windows中运行它不起作用并且可能需要(JNI?)是否有一些简单的Java类(以及其他任何必要的)的示例来捕获在Windows环境中可运行的屏幕截图?
我想使用java来使用FFMPEG或其他解决方案截取我的机器的屏幕截图.我知道linux可以在没有JNI的情况下使用ffmpeg,但是在Windows中运行它不起作用并且可能需要(JNI?)是否有一些简单的Java类(以及其他任何必要的)的示例来捕获在Windows环境中可运行的屏幕截图? FFMPEG有替代品吗?我想以比Java Robot API更快的速度截取屏幕截图,我发现它可以用于截取屏幕截图,但速度比我想要的慢.

我知道在Linux中它的工作速度非常快:

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实际上可以使其工作而无需更改上述代码.

目标是快速截取屏幕截图,但在截取“不同”的屏幕截图后停止.屏幕因某些事件而改变,例如窗口关闭等等.

使用内置的Robots类比其他Java库更容易,并且应该可以满足您的需求.

如果您需要一个平滑的视频,其中> = 30fps(每秒超过30个屏幕截图),您应首先尝试使用机器人方法以及使用异步存储屏幕截图的性能改进.

如果它不适合你,尝试使用JNA,即使它更复杂,几乎可以保证平滑的屏幕捕获.

机器人的方法

机器人类确实能够做你想做的事情,机器人大多数屏幕捕获方法的问题是节省了截图.一种方法可能如下所示:循环使用captureScreen()方法,将屏幕抓取到BufferedImage中,将其转换为字节数组,并在将图像的未来引用添加到目标文件后将其与异步文件编写器一起保存到目标文件中. ArrayList能够在存储图像数据的同时继续前进.

// 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的方法

原始问题:
How to take screenshots fast in Java?

由于链接是不好的做法,我将在此处发布示例:

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,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,(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,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,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,raster.getHeight(),pixels,0);
            }
                break;
            case DataBuffer.TYPE_USHORT:
            {
                short[] pixels = ((DataBufferUShort) buffer).getData();
                ok = GDI.GetDIBits(blitDC,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,short[] pixels,int[] pixels,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();
}

更多信息和方法

> Increasing screen capture speed when using Java and awt.Robot
> http://www.dreamincode.net/forums/topic/234896-faster-screen-capture/
> How to get over 30FPS using Java in a Screen Capture Program?
> http://ffmpeg.org

也可以看看

> http://www.thepcwizard.in/2012/12/java-screen-capturing-tutorial.html
> How to develop screen capture to video application
> 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 for screen capture?
> Java applet screen capture to a video
> Screen Capture of DirectX programs with Java

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读