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

2023-11-22

我想使用 java 使用 FFMPEG 或其他解决方案来截取我的机器的屏幕截图。我知道linux可以在没有JNI的情况下使用ffmpeg,但是在Windows中运行它不起作用,并且可能需要(JNI?)是否有一些简单的Java类(以及其他任何必要的)的示例来捕获可在Windows环境中运行的屏幕截图?有没有 FFMPEG 的替代方案?我想以比 Java Robot API 更快的速度截取屏幕截图,我发现 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 来实际使其工作,而不必更改上面的大部分代码。

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


使用内置的机器人类比其他 Java 库容易得多,并且应该可以满足您的需求。

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

如果它不适合您,请尝试使用JNA也就是说(尽管它更复杂)几乎可以保证能够实现流畅的屏幕捕获。

与机器人的接触

机器人类确实能够做你想做的事情,大多数机器人屏幕捕获方法所面临的问题是saving的屏幕截图。一种方法可能如下所示:循环 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 的接触

原问题: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, 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/forums/topic/234896-faster-screen-capture/

  • 如何在屏幕捕获程序中使用 Java 获得超过 30FPS?

  • http://ffmpeg.org

See also

  • http://www.thepcwizard.in/2012/12/java-screen-capturing-tutorial.html

  • 如何开发屏幕截图转视频应用

  • 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 程序的屏幕截图

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在Windows中用Java快速截取桌面(ffmpeg等)? 的相关文章

随机推荐

  • 关于 cudaMemcpyAsync 函数

    我有一些疑问 最近在用CUDA做一个程序 在我的程序中 Host 上有一个用 std map string vector int 编程的大数据 通过使用这些数据 一些向量 int 被复制到GPU全局内存并在GPU上处理 处理后 在 GPU
  • 逆透视 SQL 表中的所有列

    我有一个包含 30 列的表 我想轻松地取消透视所有列 我知道我可以使用这个策略 SELECT col value INTO New Table FROM SELECT FROM Test Data p UNPIVOT value FOR c
  • 在页面加载时使用 javascript(无 jquery)自行调整窗口大小并居中

    这不是我们通常会做的事情 但我们正在尝试将视频加载到由 clickTag 来自横幅广告 打开的空白窗口中 并使其尽可能感觉像模态窗口 是否可以使用javascript自行调整clickTag打开的空白窗口的大小并将其置于屏幕中央 我们无法对
  • Flutter Facebook 网页登录

    我已经尝试过Flutter Facebook 登录包 它在 android 中工作正常 但在 web 中我没有被重定向到 Facebook 进行身份验证 尝试过这个软件包的人可以帮忙吗 该插件不支持网页 但有人更新了代码以支持 romulo
  • 从列表集合中删除项目而不删除

    我正在制作一个集合 我需要从集合中删除一项并使用过滤 删除的集合 这是我的代码 public class Emp public int Id get set public string Name get set List
  • 在视频 FFmpeg 上添加图像叠加

    我有一个视频 test mp4 和一个图像 test png test png是一个黑色图像 中心有一个透明的 洞 我想使用 FFmpeg 显示test png在视频上方 所以我只能看到一圈视频 如果可能的话 调整大小test png适应视
  • USSD 消息中的最大字符数是多少?

    据我了解 USSD 消息由 160 个字节组成 对于 7 位数据编码方案 最大字符数为 160 8 7 即 182 个字符 我不清楚 UCS2 编码的最大字符数是多少 通常情况下 它会类似于 160 2 但我对此有一些复杂的信息 USSD
  • SSO - SAML,成功登录后将用户重定向到指定的登录页面

    我正在实施 SSO 其中我是身份提供商 现在我能够成功登录服务提供商 但它带我到主页 我想在发布响应时指定着陆页 URL 进行了很多搜索 但找不到任何令人信服的东西 不太清楚 SAML 响应的哪个元素带有登陆页面 URL 或者是我必须指定的
  • r - 投资组合优化 -solve.QP - 约束不一致

    我正在尝试使用solve QP来解决投资组合优化问题 二次问题 总计 3 项资产 有4个限制 权重之和等于 1 投资组合预期回报率为 5 2 每项资产权重大于0 每个资产权重小于 0 5 Dmat 是协方差矩阵 Dmat lt matrix
  • 使用 HTTPBuilder POST -> NullPointerException?

    我正在尝试发出一个简单的 HTTP POST 请求 但我不知道为什么以下失败 我尝试按照示例进行操作here 我不明白我哪里错了 例外 java lang NullPointerException at groovyx net http H
  • $(document).ready() 之后立即调用什么 jQuery 事件?

    我生成了很多 HTML document ready 我有一个简单的窗口系统 但它不仅是在 document ready 还有一些 HTML 元素 不同的 JS 文件将内容放入 document ready 我希望我的窗口系统在之后生成 d
  • SQL Max(日期) 不带分组依据

    我有下表 MemberID ServDate 001 12 12 2015 001 12 13 2015 001 12 15 2015 002 11 30 2015 002 12 04 2015 我想让它看起来像这样 MemberID Se
  • 为什么从 data.table 中选择列会产生副本?

    看来从 data table 中选择列 data table结果产生基础向量的副本 我说的是非常简单的列选择 按名称 没有要计算的表达式j并且没有要子集的行i 更奇怪的是 data frame 中的列子集似乎没有创建任何副本 我正在使用 d
  • .click()方法,浏览器支持

    我想使用js方法 click 如下 document getElementById id click 但由于它的工作至关重要 我想知道哪些浏览器支持 click 方法有 我遇到的唯一一个不支持的浏览器 click 是Safari Safar
  • 如何向现有通知负载添加属性?

    在 Rails 通知中 我订阅了 process action action controller 并且想向有效负载添加更多属性 我怎样才能做到这一点 我尝试过使用append info to payload 但这似乎没有任何作用 modu
  • $.each() jQuery 中的索引起始编号

    如何启动 jQuery each 索引从 1 而不是 0 开始 我正在使用 each 函数来填充选择框 所以在这里 我想从 1 开始填充选择框中的选项 因此 根据条件 我想在第一个索引 即 0 中添加选项 each So try each
  • 无法访问 JD-Eclipse 站点:http://java.decompiler.free.fr/?q=jdeclipse [关闭]

    Closed 这个问题是无关 目前不接受答案 我无法访问java反编译器站点 http java decompiler free fr q jdeclipse 它显示 403 错误 Erreur 403 拒绝 de Traitement d
  • 在视频中的移动物体上叠加图像(增强现实/OpenCv)

    我在用FFmpeg通过此命令在视频上叠加图像 表情符号 i inputfilePath filter complex 0 1 overlay enable between t startTime endTime v1 map v0 map
  • 如何在 SSIS 包中使服务器名称动态化

    我有许多 SSIS 包 它们都连接到同一个数据库 我不想将服务器名称硬编码到每个数据库中的数据库连接中 因为它与开发服务器和实时服务器不同 这些服务器名称可能会随着时间的推移而改变 我知道您可以将其放入配置文件中 但所有这些 SSIS 包都
  • 如何在Windows中用Java快速截取桌面(ffmpeg等)?

    我想使用 java 使用 FFMPEG 或其他解决方案来截取我的机器的屏幕截图 我知道linux可以在没有JNI的情况下使用ffmpeg 但是在Windows中运行它不起作用 并且可能需要 JNI 是否有一些简单的Java类 以及其他任何必