it-swarm.com.ru

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

Я хотел бы использовать Java, чтобы сделать снимок экрана моей машины с помощью FFMPEG или другого решения. Я знаю, что linux работает с ffmpeg без JNI, но его запуск в Windows не работает и может потребовать (JNI?), Есть ли какой-нибудь пример некоторого простого класса Java (и всего остального необходимого) для захвата снимка экрана, который можно запустить в среде Windows? Есть ли какая-нибудь альтернатива FFMPEG? Я хочу делать снимки экрана быстрее, чем API-интерфейс робота Java, который, как мне показалось, работает при создании снимков экрана, но работает медленнее, чем хотелось бы.

Я знаю, что в 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, чтобы фактически заставить его работать без необходимости изменять большую часть приведенного выше кода.

Цель состоит в том, чтобы быстро сделать скриншоты экрана, но затем остановиться после того, как он сделает снимок, который "другой", иначе. экран изменился из-за какого-либо события, например, окно закрыто и т. д.

10
Setsuna

Использование встроенного класса Robots намного проще, чем другие библиотеки Java, и, вероятно, должно соответствовать вашим потребностям.

Если вам нужно плавное видео с> = 30 кадров в секунду (более 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

Оригинальный вопрос: Как быстро делать скриншоты на 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();
}

Больше информации и подходов

Смотрите также

29
flotothemoon

В соответствии с официальным документация ffmpeg вы сможете сохранить его довольно кроссплатформенным, если вы сделаете параметр file, передаваемый FFmpegFrameGrabber (который на самом деле является параметром input, который передается как опция -i для ffmpeg ) придерживайтесь различные форматы, ожидаемые каждым device .

то есть:

для Windows: dshow ожидает -i video="screen-capture-recorder"

для OSX: avfoundation ожидает -i "<screen device index>":

и для Linux: x11grab ожидает -i :<display id>+<x>,<y>.

Так что просто передав эти значения (аргументы -i) в конструктор и соответственно установив формат (через setFormat), нужно добиться цели.

1
Roberto Andrade

Вам потребуется использовать JNI или JNA для вызова некоторой комбинации CreateCompatibleBitmap, XGetImage, DirectX или OpenGL, чтобы получить снимок экрана и затем скопировать некоторые необработанные растровые данные обратно в Java. Мое профилирование показало ускорение примерно на 400% по сравнению с классом Robot при доступе к необработанным растровым данным в X11. В настоящее время я не тестировал другие платформы. Некоторый очень ранний код доступен здесь , но у меня не было много времени, чтобы поработать над ним в последнее время.

1
Alex Barker

Вы знакомы с Xuggler? Он использует FFmpeg для кодирования и декодирования. Я узнал об этом несколько месяцев назад, когда мне пришлось извлекать кадры из видео, и оно работало без сбоев.

На официальном сайте вы можете найти несколько примеров, в том числе "CaptureScreenToFile.Java". Для получения дополнительной информации перейдите по этим ссылкам:

http://www.xuggle.com/xuggler/

https://github.com/artclarke/xuggle-xuggler/tree/master/src/com/xuggle/xuggler/demos

0
H3LL0