Увеличение скорости захвата экрана при использовании Java и awt.Robot

Изменить: если у кого-то есть другие рекомендации по увеличению производительности захвата экрана, пожалуйста, не стесняйтесь делиться, так как он может полностью решить мою проблему!

Привет, разработчики,

Я работаю над некоторым основным программным обеспечением для захвата экрана для себя. На данный момент у меня есть кое-какие доказательства кода концепции /tinkering, который использует java.awt.Robot для захвата экрана как BufferedImage. Затем я делаю этот захват в течение определенного времени, а затем сбрасываю все изображения на диск. Из моих тестов я получаю около 17 кадров в секунду.

Пробный № 1

Длина: 15 секунд Захваченные изображения: 255

Пробный № 2

Длина: 15 секунд Захваченные изображения: 229

Очевидно, что это не достаточно хорошо для реального приложения захвата экрана. Тем более, что этот захват был мной, просто выбирая текст в моей среде IDE и ничего, что было графически интенсивным.

У меня есть два класса, теперь класс Main и класс "Monitor". Класс Monitor содержит метод захвата экрана. В моем основном классе есть цикл, основанный на времени, которое вызывает класс Monitor и сохраняет BufferedImage, который возвращается в ArrayList из BufferedImages. Если я модифицирую свой основной класс, чтобы создать несколько потоков, каждый из которых выполняет этот цикл, а также собирает информацию о системном времени, когда изображение было захвачено, я могу увеличить производительность? Моя идея - использовать общую структуру данных, которая автоматически сортирует кадры на основе времени захвата, когда я их вставляю, вместо одного цикла, который вставляет последовательные изображения в arraylist.

код:

Monitor

public class Monitor {

/**
 * Returns a BufferedImage
 * @return
 */
public BufferedImage captureScreen() {
    Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    BufferedImage capture = null;

    try {
        capture = new Robot().createScreenCapture(screenRect);
    } catch (AWTException e) {
        e.printStackTrace();
    }

    return capture;
}
}

Главная

public class Main {


public static void main(String[] args) throws InterruptedException {
    String outputLocation = "C:\\Users\\ewillis\\Pictures\\screenstreamer\\";
    String namingScheme = "image";
    String mediaFormat = "jpeg";
    DiscreteOutput output = DiscreteOutputFactory.createOutputObject(outputLocation, namingScheme, mediaFormat);

    ArrayList<BufferedImage> images = new ArrayList<BufferedImage>();
    Monitor m1 = new Monitor();

    long startTimeMillis = System.currentTimeMillis();
    long recordTimeMillis = 15000;

    while( (System.currentTimeMillis() - startTimeMillis) <= recordTimeMillis ) {
        images.add( m1.captureScreen() );
    }

    output.saveImages(images);

}
}

Ответ 1

Повторное использование прямоугольника экрана и экземпляров класса роботов позволит вам немного накладных расходов. Настоящим узким местом является хранение всего вашего BufferedImage в списке массивов.

Вначале я бы поставил себе задачу определить, насколько быстро ваш robot.createScreenCapture(screenRect); вызов без ввода-вывода (без сохранения или сохранения буферизованного изображения). Это даст вам идеальную пропускную способность для класса роботов.

long frameCount = 0;
while( (System.currentTimeMillis() - startTimeMillis) <= recordTimeMillis ) {
    image = m1.captureScreen();
    if(image !== null) {
        frameCount++;
    }
    try {
        Thread.yield();
    } catch (Exception ex) {
    }
}

Если окажется, что captureScreen может достичь FPS, который вам нужен, не нужно для многопоточных экземпляров робота.

Вместо того, чтобы иметь список массивов буферизованных изображений, у меня был бы список массивов фьючерсов из AsynchronousFileChannel.write.

  • Цикл захвата
    • Получить BufferedImage
    • Преобразование BufferedImage в байтовый массив, содержащий данные JPEG
    • Создайте асинхронный канал для выходного файла
    • Начните запись и добавьте немедленное возвращаемое значение (будущее) в ArrayList
  • Цикл ожидания
    • Пройдите через ArrayList of Futures и убедитесь, что все они завершены.

Ответ 2

Я предполагаю, что интенсивное использование памяти является проблемой. Вы записываете в своих тестах около 250 скриншотов. В зависимости от разрешения экрана это:

1280x800 : 250 * 1280*800  * 3/1024/1024 ==  732 MB data
1920x1080: 250 * 1920*1080 * 3/1024/1024 == 1483 MB data

Попробуйте сделать caputuring, не сохраняя все эти изображения в памяти.

Как сказал @Obicere, неплохо сохранить экземпляр Robot.