2012-01-27 26 views
6

Estoy trabajando en un proyecto de juguete de administración remota. Por ahora, puedo capturar capturas de pantalla y controlar el mouse usando la clase Robot. Las capturas de pantalla son BufferedImage instancias.Alternativas para generar un video de capturas de pantalla

Primero de todos mis requisitos: - Solo un servidor y un cliente. - El rendimiento es importante, ya que el cliente puede ser una aplicación de Android.

He pensado en abrir dos conexiones de socket, una para los comandos del sistema y del mouse y la segunda para la alimentación de video.

¿Cómo podría convertir las capturas de pantalla a una transmisión de video? ¿Debería convertirlos a un formato de video conocido o estaría bien simplemente enviar una serie de imágenes serializadas?

La compresión es otro problema. Enviar las capturas de pantalla en resolución completa daría como resultado una baja velocidad de cuadro, de acuerdo con mis pruebas preliminares. Creo que necesito al menos 24 fps para percibir el movimiento, por lo que tengo que reducir y comprimir. Podría convertir el BufferedImages en archivos jpg y luego establecer la tasa de compresión, pero no quiero almacenar los archivos en el disco, sino que deben vivir solo en la memoria RAM. Otra posibilidad sería serializar instancias (que representan una captura de pantalla sin comprimir) a un GZipOutputStream. ¿Cuál es el enfoque correcto para esto?

En resumen:

  • En caso de que recomiendan la "serie de imágenes", enfoque, ¿cómo los serializar a la toma OutputStream?
  • Si su proposición es convertir a un formato de video saber, ¿qué clases o bibliotecas están disponibles?

Gracias de antemano.

ACTUALIZACIÓN: mis pruebas, cliente y servidor en la misma máquina
-Images Buffered serializadas en pantalla completa (solo dimensión, tipo e int []), sin compresión: 1.9 fps.
-fáciles imágenes de pantalla a través de las transmisiones GZip: 2.6 fps.
-Imagenes de escala de colores (ancho 640) y flujos GZip: 6,56 fps.
-Imagen de pantalla completa y codificación RLE: 4.14 fps.
-Imagen de escala de colores y codificación RLE: 7.29 fps.

+0

Si utiliza su idea con imágenes comprimidas JPEG, no hay necesidad de crear archivos en absoluto: ImageIO funciona con transmisiones, por lo que puede "guardar" su imagen directamente en un socket y recuperarla en el otro extremo directamente como imagen también (con un pequeño código de cableado alrededor). – Durandal

+0

@Durandal ¿Crees que ahorrará más espacio que las transmisiones GZip? –

+0

Con JPEG tiene la opción (relación de compresión), si establece la calidad lo suficientemente baja ... comprimirá más que BufferedImage + GZIP. La pregunta es: cuánta calidad va a necesitar y qué tan rápido será con esa calidad (CPU y rendimiento de red requerido). A menos que tenga un rendimiento claro y objetivos de calidad, tendrá dificultades para decidir qué usar. – Durandal

Respuesta

6

Si solo capturas de pantalla, no las comprimiría usando un esquema de compresión de video, lo más probable es que no quieras la compresión con pérdida (borrosa detalles en texto pequeño, etc. son los defectos más comunes). Para conseguir un viable "Escritorio remoto" sentir, recordar el enviado previamente pantalla y enviar sólo la diferenciapara llegar a la siguiente. Si nada (o muy poco) cambia entre fotogramas esto es muy eficiente. Sin embargo, no va a funcionar bien en ciertas situaciones, como reproducción de un vídeo, juegos o desplazarse mucho en un documento.

Compresión de la diferencia entre dos BufferedImage se puede hacer con métodos más o menos elaborados, un método muy simple, pero razonablemente eficaz es simplemente restar una imagen de la otra (lo que resulta en ceros donde son idénticos) y comprimir el resultado con RLE simple (codificación de longitud de ejecución).

Reducir la precisión del color se puede utilizar para reducir aún más la cantidad de datos (dependiendo del caso de uso se pueden omitir los N bits menos significativos de cada canal de color, la mayoría de las aplicaciones GUI no parecen muy diferentes si se reducen los colores 24 bits a 15 bits).

+0

Pensé que los formatos de video proporcionarán Key Frame Compression, que es básicamente lo que está proponiendo, y otros beneficios. –

+0

Todos los populares esquemas de compresión de video realmente lo hacen. La diferencia (decisiva) aquí es que los compresores de video están optimizados para * Video *, y todos ellos aplican la compresión * lossy *. No se manejan demasiado bien con el tipo de gráficos que comúnmente se muestran en un escritorio (texto), que pueden o no ser un problema para el caso de uso. – Durandal

+0

Voy a probar su técnica de sustracción, parece muy amigable con la compresión. –

2

Creo que describió una buena solución en su pregunta. Convierta las imágenes a jpeg, pero no las escriba como archivos en el disco. Si desea que sea un formato de video conocido, use M-JPEG. M-JPEG es una secuencia de marcos jpeg en un formato estándar. Muchas cámaras digitales, especialmente las más antiguas, guardan videos en este formato.

Usted puede obtener alguna información acerca de cómo jugar un flujo M-JPEG de las respuestas de esta pregunta: Android and MJPEG

Si el ancho de banda es un problema, entonces usted desea utilizar un sistema de compresión entre cuadros como MPEG-2, h.264 o similar. Eso requiere mucho más procesamiento que M-JPEG, pero es mucho más eficiente.

3

En primer lugar, podría sugerir capturar solo una pequeña parte de la pantalla, en lugar de reducir y perder información, quizás con algo así como una ventana deslizante que se puede mover empujando los bordes con un cursor. Sin embargo, esta es solo una pequeña sugerencia de diseño.

En cuanto a la compresión, creo que una serie de imágenes no se comprimirían por separado ni con un esquema de compresión de video decente, especialmente porque los marcos probablemente se mantendrán consistentes entre capturas en este escenario.

Una opción sería usar Xuggle, que es capaz de capturar el escritorio a través de Robot en varios formatos de video afaiu, pero no puedo decir si puede transmitir y decodificar con esto.

Para capturar imágenes JPEG y la conversión de ellos, entonces también se puede utilizar this.

Streaming estos videos parece ser un poco más complicado, sin embargo.

Además, parece que el Java Media Framework abandonada soporta esta funcionalidad.

Mi conocimiento en esta área no es fantástico tbh, lo siento mucho si he perdido el tiempo, pero parece una información más útil sobre la posibilidad de utilizar Xuggle como se compiló una pantalla here. Esto también parece vincularse con sus propias notas sobre los enfoques existentes.

Si no necesita ser puro Java Creo que todo esto sería mucho más fácil usando sólo mediante la interacción con una herramienta de captura de pantalla nativa ...

tal vez sería más fácil simplemente enviar el vídeo como una serie de jpegs después de todo! Siempre puedes implementar tu propio esquema de compresión si te sientes un poco loco ...

+0

Ha intentado enviar objetos de titular serializado que contienen datos BufferedImage a pantalla completa, a través de las transmisiones GZip. Incluso ejecutando el cliente y el servidor en la misma máquina, la velocidad de cuadros fue muy baja (alrededor de 1 fps). Muy probablemente tendré que ir para el video. –

5
  • Romper la pantalla hacia arriba en un cuadrículas (o tiras)
  • Enviar sólo el cuadrado de la cuadrícula si es diferente de la anterior

// 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) 
    } 
} } 

No enviar los objetos java serializados solo envían los datos de la imagen.

ByteArrayOutputStream imgBytes = new ByteArrayOutputStream(); 
ImageIO.write(bufferedImage, "jpg", imgBytes); 
imgBytes.flush(); 
+0

+1 para proporcionar un fragmento sobre cómo escribir jpeg sin crear un archivo en el disco. –

0

Si usted está tratando de conseguir el vídeo de 24 fps entonces no hay razón para no utilizar los códecs de vídeo modernas. ¿Por qué intentar y recrear esa rueda?

Xuggler funciona bien para la codificación de video h264 y parece que satisfaría sus necesidades.

Cuestiones relacionadas