2012-01-27 12 views
6

Sto lavorando a un progetto di giocattoli di amministrazione remota. Per ora, sono in grado di catturare schermate e controllare il mouse usando la classe Robot. Le schermate sono istanze BufferedImage.Alternative per la generazione di un feed video da screenshot

Prima di tutto, i miei requisiti: - Solo un server e un client. - Le prestazioni sono importanti, poiché il client potrebbe essere un'app Android.

Ho pensato di aprire due connessioni socket, una per i comandi del mouse e di sistema e la seconda per il feed video.

Come posso convertire gli screenshot in uno streaming video? Dovrei convertirli in un formato video conosciuto o sarebbe giusto inviare solo una serie di immagini serializzate?

La compressione è un altro problema. L'invio delle schermate catturate a piena risoluzione comporterebbe un basso frame rate, secondo i miei test preliminari. Penso di aver bisogno di almeno 24 fps per percepire il movimento, quindi devo effettuare il downscale e comprimerlo. Potrei convertire il file BufferedImages in jpg e quindi impostare il tasso di compressione, ma non voglio archiviare i file sul disco, ma dovrebbero vivere solo nella RAM. Un'altra possibilità sarebbe quella di serializzare le istanze (che rappresentano uno screenshot non compresso) in un GZipOutputStream. Qual è l'approccio corretto per questo?

In sintesi:

  • Nel caso in cui si consiglia la "serie di immagini" l'approccio, come sarebbe li serializzare alla presa OutputStream?
  • Se la tua proposta è quella di convertire in un formato video noto, quali classi o librerie sono disponibili?

Grazie in anticipo.

UPDATE: il mio test, client e server sulla stessa macchina
schermo Full BufferedImages serializzati (sola dimensione, tipo e int []), senza compressione: 1,9 fps.
-tutte le immagini dello schermo tramite stream GZip: 2.6 fps.
-Immagini scalate (larghezza 640) e flussi GZip: 6,56 fps.
- Immagini schermo intero e codifica RLE: 4,14 fps.
-Immagini scalate e codifica RLE: 7,29 fps.

+0

Se si utilizza la propria idea con immagini compresse JPEG, non è necessario creare file - ImageIO funziona con flussi, quindi è possibile "salvare" l'immagine direttamente in un socket e recuperarla direttamente dall'altra parte come immagine pure (con un piccolo codice di cablaggio in giro). – Durandal

+0

@Durandal Pensi che farà risparmiare più spazio rispetto ai flussi GZip? –

+0

Con JPEG avete la scelta (rapporto di compressione), se avete impostato una qualità sufficientemente bassa ... comprimerà più di BufferedImage + GZIP. La domanda è: quanta qualità avrà bisogno e quanto velocemente sarà con quella qualità (CPU e troughput di rete richiesto). A meno che tu non abbia obiettivi chiari di prestazioni e qualità, avrai difficoltà a decidere cosa usare. – Durandal

risposta

6

Se la sua sola schermata cattura, non li comprimere utilizzando uno schema di compressione Video, molto probabilmente non vuoi una compressione con perdita (sfocato) i dettagli nel piccolo testo ecc sono i difetti più comuni). Per ottenere un "desktop remoto" funzionale, ricorda lo screenshot inviato in precedenza e invia solo la differenza per passare a quella successiva. Se nulla (o molto poco) cambia tra i frame, questo è molto efficiente. Tuttavia non funzionerà bene in determinate situazioni, come la riproduzione di un video, un gioco o lo scorrimento di un documento.

La compressione della differenza tra due BufferedImage può essere eseguita con metodi più o meno elaborati, un metodo molto semplice, ma ragionevolmente efficace è semplicemente quello di sottrarre un'immagine dall'altra (ottenendo zeri ovunque siano identici) e comprimendo il risultato con semplice RLE (codifica della durata della corsa).

La riduzione della precisione del colore può essere utilizzata per ridurre ulteriormente la quantità di dati (in base al caso d'uso è possibile omettere gli N bit meno significativi di ogni canale di colore, per la maggior parte delle applicazioni GUI non è molto diverso se si riducono i colori da 24 bit a 15 bit).

+0

Ho pensato che i formati video offrissero la compressione dei fotogrammi chiave, che è sostanzialmente ciò che stai proponendo e altri vantaggi. –

+0

Tutti i popolari schemi di compressione video fanno proprio questo. La differenza (decisiva) qui è che i compressori video sono ottimizzati per * Video *, e tutti applicano la compressione * lossy *. Non si comportano molto bene con il tipo di grafica comunemente visualizzata su un desktop (testo) - che potrebbe essere o meno un problema per il caso d'uso. – Durandal

+0

Proverò la tecnica della sottostringa, mi sembra molto facile da usare. –

2

Penso che tu abbia descritto una buona soluzione nella tua domanda. Converti le immagini in jpeg, ma non scriverle come file sul disco. Se vuoi che sia un formato video conosciuto, usa M-JPEG. M-JPEG è un flusso di fotogrammi jpeg in un formato standard. Molte fotocamere digitali, soprattutto quelle più vecchie, salvano video in questo formato.

È possibile ottenere alcune informazioni su come svolgere un flusso M-JPEG dalle risposte di questa domanda: Android and MJPEG

Se la larghezza di banda di rete è un problema, allora si vorrà utilizzare un sistema di compressione inter-frame come MPEG-2, h.264 o simile. Ciò richiede molta più elaborazione rispetto all'M-JPEG ma è molto più efficiente.

3

In primo luogo, potrei suggerire di catturare solo una piccola parte dello schermo, piuttosto che il downscaling e potenzialmente perdere informazioni, magari con qualcosa come una finestra scorrevole che può essere spostata spingendo i bordi con un cursore. Questo è davvero solo un piccolo suggerimento sul design.

Per quanto riguarda la compressione, penserei che una serie di immagini non si comprime separatamente e con uno schema di compressione video decente, soprattutto perché i fotogrammi sono probabilmente coerenti tra le acquisizioni in questo scenario.

Un'opzione potrebbe essere quella di utilizzare Xuggle, che è in grado di acquisire il desktop tramite Robot in una serie di formati video afaiu, ma non posso dire se è possibile eseguire lo streaming e decodificare con questo.

Per catturare jpeg e convertirli, è inoltre possibile utilizzare this.

Lo streaming di questi video sembra essere un po 'più complicato, però.

Inoltre, sembra che il Java Media Framework abbandonato supporti questa funzionalità.

La mia conoscenza in questo settore non è fantastica, tbh, mi spiace se ho perso tempo, ma sembra che alcune informazioni più utili sulla fattibilità dell'uso di Xuggle come screensaver siano state compilate here. Questo sembra anche collegarsi alle proprie note sugli approcci esistenti.

Se non ha bisogno di essere puro Java Devo ammettere che questo sarebbe tutto molto più semplice utilizzando solo interfacciando con uno strumento di cattura dello schermo nativa ...

Forse sarebbe stato più semplice di inviare video come serie di jpeg dopo tutto! Puoi sempre implementare il tuo schema di compressione se ti senti un po 'pazzo ...

+0

Provato a inviare oggetti di supporto serializzati contenenti dati BufferedImage a schermo intero, su flussi GZip. Anche con client e server in esecuzione nella stessa macchina, il framerate era molto basso (circa 1 fps). Molto probabilmente dovrò andare per il video. –

5
  • rompere lo schermo in su in un quadrati della griglia (o strisce)
  • Invia solo il quadrato della griglia se è diverso dal precedente

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

Non inviare gli oggetti java serializzati inviano semplicemente i dati dell'immagine.

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

+1 per fornire uno snippet su come scrivere jpeg senza creare file su disco. –

0

Se si sta cercando di ottenere il video 24fps allora non c'è ragione per non utilizzare moderni codec video. Perché provare a ricreare quella ruota?

Xuggler funziona bene per la codifica del video h264 e suona come se fosse utile per le vostre esigenze.

Problemi correlati