Альтернативы для создания видеопотока со скриншотов
Я работаю в проекте игрушек удаленного администрирования. На данный момент я могу захватывать скриншоты и управлять мышью с помощью Robot
класса. Скриншоты BufferedImage
экземпляров.
прежде всего, мои требования: - Только сервер и клиент. - Производительность важна, так как клиент может быть Android-приложением.
Я думал об открытии двух сокетов, один для мыши и системных команд, а второй для видео кормить.
как я могу конвертировать скриншоты в видеопоток? Следует ли конвертировать их в известный формат видео или можно просто отправить серию сериализованных изображений?
сжатие-еще одна проблема. Отправка снимков экрана в полном разрешении приведет к низкой частоте кадров, согласно моим предварительным тестам. Я думаю, что мне нужно по крайней мере 24 fps, чтобы воспринимать движение, поэтому я должен как масштабировать, так и сжимать. Я мог бы преобразовать BufferedImages
в файлы jpg, а затем установите коэффициент сжатия, но я не хочу хранить файлы на диске, они должны жить только в памяти. Другой возможностью было бы сериализовать экземпляры (представляющие несжатый скриншот) в GZipOutputStream. Каков правильный подход для этого?
подведем итоги:
- если вы рекомендуете подход "серии изображений", как бы вы сериализовали их в сокет
OutputStream
? - если ваше предложение преобразовать в знать видео формат, какие классы или библиотеки доступны?
спасибо заранее.
UPDATE: мои тесты, клиент и сервер на одной машине
- Полноэкранные сериализованные Буферизованные изображения (только размер, тип и int []) без сжатия: 1.9 fps.
- полноэкранные изображения через потоки GZip: 2.6 fps.
- Уменьшенные изображения (ширина 640) и потоки GZip: 6.56 fps.
- Полноэкранные изображения и кодировка RLE: 4.14 fps.
- Уменьшенные изображения и RLE кодировка: 7.29 fps.
5 ответов
Если его просто захватывает экран, я бы не сжимал их с помощью схемы сжатия видео, скорее всего, вы не хотите сжатия с потерями (размытые детали в небольшом тексте и т. д. являются наиболее распространенными дефектами). Для получения работоспособного" удаленного рабочего стола", помните ранее отправленный скриншот и отправить только разница чтобы добраться до следующего. Если ничего (или очень мало) не меняется между кадрами, это очень эффективно. Однако это не будет хорошо работать в определенных ситуациях, таких как воспроизведение видео, игры или прокрутка много в документе.
сжатие разницы между двумя буферными изображениями может быть сделано с помощью более или менее сложных методов, очень простой, но достаточно эффективный метод-просто вычесть одно изображение из другого (в результате чего нули везде одинаковы) и сжать результат с помощью простого RLE (кодирование длины выполнения).
уменьшение точности цвета можно использовать для дальнейшего уменьшения количества данных (в зависимости от используйте случай, когда вы можете опустить наименее значимые n бит каждого цветового канала, для большинства приложений GUI выглядят не намного иначе, если вы уменьшите цвета с 24 бит до 15 бит).
- разбить экран на квадраты (или полосы)
- только отправить квадрат сетки, если он отличается от предыдущего
// server start
sendScreenMetaToClient(); // width, height, how many grid squares
...
// server loop ImageBuffer[] prevScrnGrid while(isRunning) {
ImageBuffer scrn = captureScreen();
ImageBuffer[] scrnGrid = screenToGrid(scrn);
for(int i = 0; i < scrnGrid.length; i++) {
if(isSameImage(scrnGrid[i], prevScrnGrid[i]) == false) {
prevScrnGrid[i] = scrnGrid[i];
sendGridSquareToClient(i, scrnGrid[i]); // send the client a message saying it will get grid square (i) then send the bytes for grid square (i)
}
} }
не отправляйте сериализованные объекты java, просто отправляйте данные изображения.
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
ImageIO.write( bufferedImage, "jpg", imgBytes );
imgBytes.flush();
во-первых, я мог бы предложить захватывать только небольшую часть экрана, а не масштабирование и потенциальную потерю информации, возможно, с чем-то вроде скользящего окна, которое можно перемещать, нажимая на края курсором. Это действительно просто небольшое дизайнерское предложение.
Что касается сжатия, я бы подумал, что серия изображений не будет сжиматься отдельно, а также с приличной схемой сжатия видео, тем более, что кадры, вероятно, останутся согласованность между захватами в этом сценарии.
одним из вариантов было бы использовать Xuggle, который способен захватывать рабочий стол с помощью робота в нескольких видеоформатах afaiu, но я не могу сказать, можете ли вы передавать и декодировать с этим.
для захвата JPEG и преобразования их, то вы также можете использовать этой.
потоковая передача этих видео, кажется, немного сложнее, хотя.
кроме того, кажется, что заброшенный Java-носитель Framework поддерживает эту функцию.
мои знания в этой области не являются фантастическими tbh, поэтому извините, если я потратил ваше время, но похоже, что была собрана еще одна полезная информация о возможности использования Xuggle в качестве screensharer здесь. Это также, как представляется, связано с их собственными замечаниями о существующих подходах.
Если это не должно быть чистой Java, я считаю, что все это было бы намного проще использовать, просто взаимодействуя с собственным захватом экрана инструмент...
может быть, было бы проще просто отправить видео в серии изображений в конце концов! Вы всегда можете реализовать свою собственную схему сжатия, если вы чувствуете себя немного сумасшедшим...
Я думаю, вы описали хорошее решение в своем вопросе. Преобразуйте изображения в jpeg, но не записывайте их в виде файлов на диск. Если вы хотите, чтобы это был известный формат видео, используйте M-JPEG. M-JPEG - это поток кадров JPEG в стандартном формате. Многие цифровые камеры, особенно старые, сохраняют видео в этом формате.
вы можете получить некоторую информацию о том, как играть в поток M-JPEG из ответов на этот вопрос: Android и MJPEG
Если пропускная способность сети является проблемой, то вы хотите использовать систему сжатия между кадрами, такие как MPEG-2, h.264 или что-то в этом роде. Это требует гораздо большей обработки, чем M-JPEG, но гораздо более эффективно.
Если вы пытаетесь получить видео 24fps, то нет причин не использовать современные видеокодеки. Зачем пытаться воссоздать колесо?
Xuggler отлично работает для кодирования видео h264 и звучит так, как будто это будет служить вашим потребностям.