Увеличение скорости захвата экрана при использовании 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 в байтовый массив, содержащий данные 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.