Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich schreibe an einem Programm, das ähnlich wie TeamViewer funktionieren soll(Also Desktop übertragung usw.). Momentan erstelle ich immer Screenshots mit Robot.createScreenCapture(Rectangle) und verschicke diese dann zu dem Server. Jedoch dauert dies sehr lang und braucht pro Bild etwa 4 Sekunden um es su verschicken.
Gibt es in Java eine Möglichkeit, das Bild zu verkleinern (Also z.B. nur jeden zweiten Pixel verschicken o.ä.), dass es dann schneller wird?? Oder kann man dieses Problem auch anders lösen??
Was bringt mir das, wenn ich es als PNG abspeichere?? Es wird ja dadurch nicht schneller oder?? Dann müsste ich es abspeichern, laden und verschicken, sind mehr Schritte als vorher. Oder wird die Größe dadurch stark verkleinert und insgesammt ist es dann doch schneller????
Netzwerkübertragung ist immer wesentlich teuerer als Speicheroperationen. PNG Bilder sind um viele Faktoren kleiner als unkromprimierte Bitmaps, ein Bildkompressionsverfahren wie eben zB PNG reduziert den Traffic also schon deutlich.
Übrigens, nicht als PNG (physikalisch) abspeichern, sondern nur In-Memory und die komprimierten Bits dann verschicken.
auch ein PNG wird dich nicht großartig weiterbringen, du müsstest nur den Bereich senden, der sich seit dem letzten Screenshot auch wirklich verändert.
TeamViewer versendet es dann zeilenweise (also jede 4. Zeile, dann jede 3 ...) und erreicht damit dass das Bild scheinbar schneller aufgebaut wird.
Also ich habe jetzt mal mit getRGB(x,y) jedes einzelne Pixel beider Bilder(das jetztige und das vorherige) ausgelesen und in einem zweidimensionalen int-Array gespeichert. Dann habe ich es durch
Java:
if (pixel1[x][y] != pixel2[x][y])
{
image2.setRGB(x, y, 0);
}
ausgelesen. Doch nun möchte ich ja nur den Teil verschicken, der sich verändert hat. Wie kann man das jetzt machen? Wenn ich es jetzt so verschicke, habe ich trotzdem noch das ganze Bild, nur dass überall eine "0" steht, wo sich etwas verändert hat (Also Farbwert 0).
PS: Wenns geht auch ein kleines Beispiel dazu schreiben
Tut mir leid nicht ausgelesen, sondern verglichen. Hier nochmal das ganze:
Java:
for (int x = 0; x < breite; x++)
{
for (int y = 0; y < hoehe; y++)
{
pixel1[x][y] = image1.getRGB(x, y);
pixel2[x][y] = image2.getRGB(x, y);
if (pixel1[x][y] != pixel2[x][y])
{
image2.setRGB(x, y, 0);
}
}
}
Je nach Bildtyp und Bildgröße kann das getRGB so lange dauern, dass es sich nicht lohnt. Im schlimmsten Fall stellt man ohnehin fest, dass sich ALLES geändert hat, und man auch ALLES übertragen muss.
Man könnte auch sagen, dass die Entscheidung über die Frage, WAS übertragen werden muss, unabhängig von der Frage ist, WIE die Daten dann übertragen werden.
Die Bestimung der Bereiche, die sich geändert haben (könnte man als "Dirty Rectangle Detection" bezeichnen) kann beliebig kompliziert sein. Ein einfacher Pixelvergleich ist zwar einfach, aber ziemlich langsam. Ob und wie man für sowas Techniken wie KD-Trees oder irgendwas mit Hashing einsetzen kann, muss man sich noch überlegen. Mit ziemlicher Sicherheit wird das aber nur "schnell", wenn man ein bißchen in den Innereien eines BufferedImages rumwühlt (d.h. sicherstellen, dass es vom TYPE_INT_RGB ist, und sich den DataArray als int[] array holt oder so).
ich habe es jetzt einfach mal das ganze int-Array zu verschicken(Da ich nicht wusste wie das andere geht). Als ich es innerhalbt des Routers (2 Rechner unter einem Router) brauchte es pro Bild etwa 300 millisekunden, bis es an kam.
Jetzt habe ich es jedoch zwar innerhalb eine Routers probiert, aber über die externe IP-Adresse.
Jetzt gab es schon sofort das erste Problem: Alleine zum Verbinden mit dem Server, hat es 2 Minuten gedauert. Und dann sind die Bilder nicht gleichmäßig angekommen, sondern einmal 20, dann 30 Sekunden nichts, dann 30 usw. .
Kann mir jemand erklären, warum diese nur so gebündelt ankommen und zwischendrin gar nichts ist?? Ich benutze doch flush() da dürfte dies eigentlich nicht passieren... Und wieso dauert es fast 2 minuten zum verbinden?? Ich habe eine recht schnelle Leitung ( 34000 MB / s)
Ich hab noch ein Problem gefunden : Wenn ich mit createScreenCapture(rect) mehrer Screenshot mache, sind diese nicht aktuell.
Dieser wird nur alle 2 Sekunden oder so aktualisiert. Kann man diesen vielleicht irgendwie manuell aktualisieren??
Klingt insgesamt nach mehreren Baustellen... vielleicht solltest du die Probleme der Reihe nach lösen. Erstmal sicherstellen, dass die Netwerksache funktioniert. Warum dein Router manchmal 2 Minuten braucht, weiß hier niemand, und das hat vermutlich auch nichts mit Java zu tun. Dann das mit den Screenshots. Erklären, wie die bisher gemacht werden, und wie sie weiterverarbeitet werden. Dann überlegen, wie man die Sachen überträgt....
Wenn es wirklich am Router liegt, kann ich da wohl nichts ändern. Aber wie ich das mit den Screenshots hinkriege, weiß ich nicht. Ich weiß leider nicht wie ich es sonst machen soll.
Beschreib' mal wie du die Screenshots im Moment machst. Läuft da irgendein Thread, der dumpf einfach so viele Screenshots macht, wie möglich, und die ins Netzwerk stopft? Oder hast du dir da einen Mechanismus überlegt, der dafür sorgt, dass ein neuer Screenshot erst dann versendet wird, wenn der alte verschickt wurde?
Ich hatte mal ein ähnliches Programm geschrieben, und da lief es auf sowas raus wie
Code:
1s. Server wartet auf Bildanfrage
1c. Client sendet Bildanfrage
2c. Client wartet auf Bild
2s. Server empfängt Bildanfrage
3s. Server Schickt Bild raus
4s. Server geht zu 1s
3c. Client empfängt Bild
4c. Client verarbeitet Bild
5c. Client geht zu 1c
Um sicherzustellen, dass Bilder nur so schnell rausgeschickt werden, wie sie auch empfangen und verarbeitet werden können. Das ganze auch für mehrere Clients und unterschiedliche Bildtypen ... also in Wirklichkeit etwas komplizierter, als es hier aussieht
Ich habe auch schon probiert, immer einen neuen Robot zu machen, geht leider auch nicht.
Schritte:
1c. Client wartet auf Bildanfrage
1s. Server sendet Bildanfrage
2s. Server wartet auf Bilder
2c. Client empfängt Bildanfrage
3c. (Code) :
1. Thread schläft 200 millisekunden
2. Robot erzeugt Screenshot und speichert ihn im BufferedImage image
3. BufferedImage wird in Pixel aufgeteilt und in dem zweidimensionalen int-Array gespeichert.
4. ObjectOutputStream verschickt das Bild(Eigentlich das int-Array)
3s. Server bekommt Bild und zeigt es an
4c. Code wird so lange ausgeführt (und Server empfängt so lange) , bis der Server schreibt, dass der Client aufhören soll.
Ja, was der Code mit dem x==20 und dem System.gc() und so dort soll erschließt sich mir nicht so ganz, aber... dort erkennt man jetzt keine Vorkehrungen, die verhindern, dass z.B. pro Sekunde 5 Bilder gemacht und verschickt werden sollen, obwohl z.B. nur 2 Bilder pro Sekunde verschickt und auf der anderen Seite verarbeitet werden können...
Sollte x=20 sein sind das ja für den Snippet jeweils schon mind. 300ms Wartezeit.
Das bedeutet in eine Sekunde würden 3 solche Wartezeiten reinpassen, wenn wir davon ausgehen, dass das Bilder erzeugen und verschicken für jedes Bild länger als 33msec dauert, dann komme ich ziemlich genau auf 2 Bilder pro Sekunde und per Maximalwert sind überhaupt nur 3 Bilder pro Sekunde möglich.
Du solltest die Sleep-Befehle komplett loswerden, du möchtest eine möglichst Echtzeitübertragung der Bilder und bindest dann Wartezeiten ein? Das passt nicht zusammen.
Die yield-Aufrufe sollten da auch raus.
Die sleep(), yield() und gc() -Befehle waren eigentlich dazu da, dass die Bilder aktuell sind(Wenn ich mehrere Bilder schneller verschicke (bei langsamer Leitung), dann werden die Bilder immer mehr verzögert) und dass es nicht so auf den Arbeitsspeicher drückt . Ich habe sie jetzt trotzdem weg gemacht, was leider mein Problem nicht ändert. Die Bilder sind leider nicht aktuell. Es werden etwa 6 Bilder pro Sekunde verschickt (Innerhalb des Routers). Doch wenn ich beim Clienten z.B. ein Programm starte und man es dort schon sieht, dauert es noch etwa 5 Sekunden, bis man es beim Server sieht. (Obwohl die Bilder fast gleich losgeschickt werden und ankommen)
Ich bin kein Netzwerkexperte, aber ... wenn der Client Bilder schneller rausschicken will, als das Netzwerk bwz. der Server verarbeiten kann, dann liegen liegen diese Bilder ja noch irgendwo in einem Puffer. D.h. wenn man dann ein neues, geändertes Bild (mit der gestarteten Applikation) rausschickt, dann KÖNNTE es sein, dass erstmal noch ein paar Sekunden lang "alte" Bilder beim Server ankommen. Aus genau diesem Grund hatte ich damals dieses strenge, "Handshake-artige" Verfahren eingebaut, wo der Empfänger jedes Bild explizit anfordert (und das NUR wenn er das letzte Bild schon fertig verarbeitet hat) und der Sender NUR Bilder rausschickt, wenn vorher eine Anfrage kam.
Etwas ... drastisch formuliert: Wenn in deinem Code kein "import java.util.concurrent.*" steht, ist das (für mich) schon dubios. Aber vielleicht gibt es auch eine gaaanz einfache Alternative, auf die ich wegen mangelnder Netzwerkkenntnisse damals nicht gekommen bin
Erstmal danke, ich werde mal dein Verfahren ausprobieren, ob das besser klappt. Aber was du mit "import java.util.concurrent.*" meinst, weiß ich nicht. Das seh ich zum ersten mal...
Das ist ein package mit einiges Hilfsklassen, u.a. für synchronisation. Das KANN man verwenden, um eben genau das nachzubauen: Ein Thread beim Sender wartet so lange, bis ein "Image Request" gelesen wurde. Dann wird ein Bild rausgeschickt, und wieder in den Wartezustand gegangen. Auf der anderen Seite wurde der Image Request rausgeschickt, und dann auf das Bild gewartet. Sobald das Bild empfangen und verarbeitet ist, wird ein neuer Image Request gesendet.
Ich habe ein Testprogramm gechrieben, das immer eine Anfrage stellt und daraufhin der Screenshot geschickt wird. Doch leider sind die Bilder trotzdem nicht aktuell :-( Das sehe ich schon alleine durch die Ausgabe(Wieveiel Bilder es sind) beim Clienten. Die Ausgabe ist ja auch beim Server auf dem Screenshot zu erkennen, so kann man es vergleichen.
Die Bilder kommen wieder fast sofort an (vllt 100ms), jedoch bleibt die Ausgabe immer ein paar Sekunden stehen.
Wenn man beim Clienten auf die Ausgabe schaut, läuft es durchgehend weiter. Doch beim Server (Screenshot) bleibt es immer bei z.B. 20 stehen bis komischerweise output.reset() aufgerufen wird. Dann wird das Bild erst aktualisiert. Habe es getestet, indem ich alle 2 Bilder aktualisiert habe.Es kann aber auch daran liegen, dass es immer 4-5 Sekunden dauert, bis reset() fertig ist.
Wenn ich es jedoch mit "alle 20 mal" reset() mache, ist das Bild, das aktualisiert ist (also das wo anders aussieht), trotzdem nicht aktuell. Es liegt immer zwischen 15 und 20 Bildern zurück. Aber wie bereits gesagt kommen die Bilder fast synchron an.
Hier mal der Quellcode von meinem Testprogramm: (Vielleicht wills ja mal jemand testen, obs bei ihm geht)
Server:
Java:
package de.kuehne.writeimage;
import java.awt.AWTException;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Server {
private int x;
private int y;
public static void main(String args[]) throws IOException,
InterruptedException
{
new Server().los();
}
public void los() throws IOException, InterruptedException
{
ServerSocket sock = new ServerSocket(5005);
Socket socket = sock.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
PrintWriter writer = new PrintWriter(socket.getOutputStream());
int width = 1024;
int height = 768;
JFrame frame = new JFrame();
frame.setSize(width, height);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
Graphics g;
frame.add(panel);
System.out.println("erstellt");
BufferedImage image = null;
try
{
image = new Robot().createScreenCapture(new Rectangle(0, 0, width,
height));
}
catch (AWTException e1)
{
e1.printStackTrace();
}
while (!Thread.interrupted())
{
writer.println("-50");
writer.flush();
try
{
x++;
int pixel[][] = (int[][]) in.readObject();
for (int x = 0; x < (width - 1); x++)
{
for (int y = 0; y < (height - 1); y++)
{
image.setRGB(x, y, pixel[x][y]);
}
}
y++;
System.out.println("vor zeichnen");
g = panel.getGraphics();
g.drawImage(image, 0, 0, null);
System.out
.println("empfangen : " + x + " gezeichnet: " + y);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
}
Client:
Java:
package de.kuehne.writeimage;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.swing.ImageIcon;
public class Client {
public static void main(String args[]) throws AWTException, IOException
{
new Client().los();
}
public void los() throws AWTException, IOException
{
Robot robot = new Robot();
Socket sock;
sock = new Socket("localhost", 5000);
Rectangle rect = new Rectangle();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
rect.x = 0;
rect.y = 0;
rect.width = dim.width;
rect.height = dim.height;
ObjectOutputStream ob = new ObjectOutputStream(sock.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(sock
.getInputStream()));
int x = 0;
while (!Thread.interrupted())
{
while (!reader.ready())
{
}
if (x == 20)
{
x = 0;
ob.reset();
}
String s = reader.readLine();
if (s.equals("-50"))
{
Image image = robot.createScreenCapture(rect);
ImageIcon images = new ImageIcon(image);
ob.writeObject(images);
}
x++;
}
}
}
Mit einigen Anpassungen (Port, ImageIcon statt int[][]) gehts. Das Zeichnen sollte eigentlich nur in einer Überschriebenen paintComponent-Methode passieren (nicht getGraphics auf einer Component aufrufen). Inwieweit es dort Probleme geben kann, weil das alles im selben Thread passiert, weiß ich nicht. Jedenfalls könnte ein Grund für die Aussetzer auch sein, dass der Speicher volläuft (schau dir mal die Speicherauslastung an....)
Tut mir Leid, die Klassen haben leider nicht ganz gestimmt. Ich nehme ein int[][] auch beim Clienten (Ist auf dem anderen Rechner). Und der Port stimmt natürlich auch überein. Probier es mal bitte mit einem int[][]-Array beim Clienten (Und natürlich Server).
Hab' gerade nicht so viel Zeit (und bin auch die nächsten Tage nicht so oft hier) aber vielleicht kann man das Problem eingrenzen, indem man es erstmal mit kleineren Bildern (300x300 oder 500x500) testet. Das ganze mal in einem Profiler (VisualVM oder so) laufen lassen könnte auch Rückschlüsse darauf erlauben, wo er denn genau hängt. Das mit dem x==20 hat sich mir aber immernoch nicht erschlossen...?
Durch x == 20 (genau ooutputs.reset() ) lösche ich den gespeicherten Inhalt des ObjectOutputStreams. Wenn ich das nicht mache, kommt nach einiger Zeit OutOfMemorieException. Und ich werde es mal mit kleineren Bilder prbieren
Wenn es einen OutOfMemoryError gibt, ist da mit ziemlicher Sicherheit noch irgendwo ein Fehler... Falls es nicht sooo sehr eilt: Ab nächsten Montag könnt' ich nochmal genauer schauen... Ggf. den Thread dann nochmal uppen oder mit dem aktuellen Stand neu aufmachen, falls bis dahin niemand anderes was cleveres dazu sagen kann....
Ich habe mal einen Test gemacht, indem ich beim Clienten und beim Server jedes einzelne Bild abgespeichert habe. Jetzt weiß ich zumindest was das Problem ist:
Der Client macht alle Bilder richtig, doch beim verschicken stimmt etwas nicht. Das Bild bleibt beim Server immer wie das erste (egal wie es sich beim Clienten verändert), bis beim Clienten ObjectOutputStream.reset() aufgerufen wird. Dann stimmt es wieder perfekt überein. (Also dieses eine Bild) Die nächsten sind dann wieder alle wie das, was nach dem reset() verschickt wurde. Erst wenn dann wieder reset() aufgerufen wird, stimmt es wieder usw.
Jetzt habe ich das Problem gefunden, jetzt fehlt nur noch die Lösung Nach jedem mal reset() aufrufen kann man fast vergessen, da es immer etwa 4-5 sekunden braucht, bis es das gemacht hat. Dann ist es ja keine richtige Bild-zu-Bild - Übertragung, sondern einfach nur Screenshots...
Also, ich habe jetzt nochmal das, was du zuletzt gepostet hattests, korrigiert und mit 300x300-Bildern über localhost getestet - und das funktioniert bei mir erstmal :bahnhof: Keine Verzögerungen, keine falschen Bilder...
Java:
import java.awt.AWTException;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RobotServer {
private int x;
private int y;
public static void main(String args[]) throws IOException,
InterruptedException
{
new RobotServer().los();
}
public void los() throws IOException, InterruptedException
{
ServerSocket sock = new ServerSocket(5005);
Socket socket = sock.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
PrintWriter writer = new PrintWriter(socket.getOutputStream());
int width = 300;
int height = 300;
JFrame frame = new JFrame();
frame.setSize(width, height);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
Graphics g;
frame.add(panel);
System.out.println("erstellt");
BufferedImage image = null;
try
{
image = new Robot().createScreenCapture(new Rectangle(0, 0, width,
height));
}
catch (AWTException e1)
{
e1.printStackTrace();
}
while (!Thread.interrupted())
{
writer.println("-50");
writer.flush();
try
{
x++;
int pixel[][] = (int[][]) in.readObject();
for (int x = 0; x < (width - 1); x++)
{
for (int y = 0; y < (height - 1); y++)
{
image.setRGB(x, y, pixel[x][y]);
}
}
y++;
System.out.println("vor zeichnen");
g = panel.getGraphics();
g.drawImage(image, 0, 0, null);
System.out
.println("empfangen : " + x + " gezeichnet: " + y);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
}
Java:
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.swing.ImageIcon;
public class RobotClient {
public static void main(String args[]) throws AWTException, IOException
{
new RobotClient().los();
}
public void los() throws AWTException, IOException
{
Robot robot = new Robot();
Socket sock;
sock = new Socket("localhost", 5005);
Rectangle rect = new Rectangle();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
rect.x = 0;
rect.y = 0;
rect.width = 300; //dim.width;
rect.height = 300; //dim.height;
ObjectOutputStream ob = new ObjectOutputStream(sock.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(sock
.getInputStream()));
int x = 0;
int width = 300;
int height = 300;
while (!Thread.interrupted())
{
while (!reader.ready())
{
}
if (x == 20)
{
x = 0;
ob.reset();
}
String s = reader.readLine();
if (s.equals("-50"))
{
Image image = robot.createScreenCapture(rect);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
bi.getGraphics().drawImage(image,0,0,null);
int pixel[][] = new int[width][height];
for (int xx = 0; xx < (width - 1); xx++)
{
for (int y = 0; y < (height - 1); y++)
{
pixel[xx][y] = bi.getRGB(xx, y);
}
}
//ImageIcon images = new ImageIcon(image);
//ob.writeObject(images);
ob.writeObject(pixel);
ob.flush();
}
x++;
}
}
}
Ach, sorry, ich dachte der Robot liefert nur ein Image zurück. Aber eigentlich sollte das mit jeder Art von BufferedImage funktionieren. Woran es genau lag, dass es nicht funktioniert hat, wenn man direkt das BI vom Robot nimmt, weiß ich spontan leider auch nicht ???:L
Wie bekommt es Teamviewer hin, die Bilder so schnell zu übertragen?? Ich habe es mal mit einem Kumpel getestet und es hat für ein Bild über 10min gedauert... Die Übertragung mit Teamviewer klappt jedoch recht gut...
Da könnte man ein ganzes Buch drüber schreiben Ein paar der Punkte wurden witer oben ja schon genannt:
- Nur übertragen, was sich auch geändert hat - dafür gibt's etliche potentiell geeignete Datenstrukturen (hashing, KD-Trees, usw)
- Die Bilddaten komprimieren - die meisten Flächen auf einem "normalen" Desktop sind einfarbig
- Etwas schnelleres als den Robot verwende (direktes auslesen des Grafikkartenspeichers per JNI oder so)
- Keine Konvertierung von Image in int[][] und zurück
- Etwas schnelleres als einen ObjectOutputStream verwenden (d.h. einen einfachen OutputStream, mit einem eigenen Protokoll)
- ...
- ...
- ...
Ist ein komprimiertes Bild kleiner, als das int-array??
Und mit dem nur übertragen was sich geändert hat. Wie soll man das machen?? Ich könnte ein int-array nehmen und alles was gleich ist durch eine -1 kennzeichnen, da wird es aber nicht viel kleiner...
Und wie schreibt man denn ein eigenes Protokoll über einen OutputStream?? Der muss ja dann auch Objekte nehmen... Und wie soll das dadurch schneller werden?? Es bleibt ja das gleiche Objekt über den gleichen OutputStream...
Und mit der schnelligkeit am Clienten (erstellen usw.) bin ich eigentlich zufrieden, braucht nur etwa 5 millisekunden.
Ist ein komprimiertes Bild kleiner, als das int-array??
Im allgemeinen: Ja, und zwar deutlich. Im Moment werden ja alle Pixel verschickt. Bei 1000x1000 Pixeln mit RGBA sind das pro Bild ca. 4MB. Wenn man das ganze stattdessen komprimiert, z.B. als PNG, und dann nur "die PNG-Datei" verschickt, sind es - je nachdem ... vielleicht nur 500kb oder noch weniger.
Und mit dem nur übertragen was sich geändert hat. Wie soll man das machen??
Da gäbe es beliebig ausgefeilte Möglichkeiten. Man könnte (vereinfacht gesagt) den aktuellen und den vorheigen Screenshot vergleichen, und dann feststellen, dass sich von dem 1000x1000-Bild nur ein Bereich der größe 100x100 verändert hat. NUR diesen Bereich könnte man dann als PNG übertragen (mit der Zusatzinformation, an welcher Stelle auf dem Bildschirm der Client dieses "Tile" (Kachel) dann malen soll). So ein "Tiling" könnte (!) ohnehin die "gefühlte Geschwindigkeit" verbessern: Wenn man immer das komplette Bild überträgt, braucht das jedesmal sehr lange. Wenn man stattdessen den Bildschirm z.B. in 10x10 Kacheln aufteilt, und die einzeln überträgt, kommt beim Client zumindest schonmal was an - noch nicht das ganze Bild, aber man sieht immerhin schon mal was...
Und wie schreibt man denn ein eigenes Protokoll über einen OutputStream?? Der muss ja dann auch Objekte nehmen... Und wie soll das dadurch schneller werden?? Es bleibt ja das gleiche Objekt über den gleichen OutputStream...
Das bezog sich auf die obigen Punkte: Man weiß nicht genau, was ein ObjectOutputStream genau verschickt, wenn man ihm einen int[][] array gibt. Es wird sicher sehr kompakt und effizient sein, aber stattdessen ein PNG (als Rohdaten, also einfach als ein byte[] array) wird vermutlich schneller sein. Falls man Tiling verwendet, muss man aber zusätzlich noch die Positionen und Größen der gesendeten Tiles mitschicken, damit der Client sie richtig anzeigen kann. Das würde man dann ggf. mit einem eigenen Protokoll machen. Alternativ dazu mit einer Klasse, die einfach "Serializable" ist, und DIE schickt man dann über einen ObjectOutputStream
Code:
class Tile implements Serializable
{
private int x,y,width,height;
private byte[] pngData;
...
}
Alles nur GANZ grobe Ideen. Da kann man eine Menge Arbeit reinstecken, wenn man es "vernünftig" machen will...
auch ein PNG wird dich nicht großartig weiterbringen, du müsstest nur den Bereich senden, der sich seit dem letzten Screenshot auch wirklich verändert. TeamViewer versendet es dann zeilenweise (also jede 4. Zeile, dann jede 3 ...) und erreicht damit dass das Bild scheinbar schneller aufgebaut wird.
Wie bekommt es Teamviewer hin, die Bilder so schnell zu übertragen?? Ich habe es mal mit einem Kumpel getestet und es hat für ein Bild über 10min gedauert... Die Übertragung mit Teamviewer klappt jedoch recht gut...
Danke für die Antworten. Tut mir leid dass ich es erst jetzt lese, aber ich habe die Seite immer aktualisiert und erst jetzt mitbekommen dass eine neue Seite angefangen wurde >.< . Ich werde mal ausprobieren was du geschrieben hast.
Also wenn ich es richtig verstanden habe, soll ich die Bilder (durchgehend?) vergleichen(mit den RGB-Werten?). Und wenn sich etwas verändert hat, verschicke ich die Daten des Ortes, der sich verändert hat(genaue Position und Länge/Breite) und dann das PNG(nur der Teil vom Screenshot). Und der Server zeichnet dann nur diese Fläche an den richtigen Fleck .
Wie kann ich jetzt ein PNG-Bild virtuell speichern?? Also ich kann es auf der Festplatte speichern klar, aber virtuell??(wenn man das so nennen kann)
Und verstehe ich das richtig mit dem RGB-vergleich?? Oder wäre es anders besser...
Das mit dem RGB-Vergleich wäre eine Möglichkeit. Erstmal wäre das evtl. noch etwas langsam. Wenn man genauer weiß, von welchem Typ das Bild ist, kann man sich die Pixeldaten evtl. direkt als int[] array abholen, womit der Vergleich u.U. schneller werden könnte, aber das ist nur eine Optimierung, die man nachträglich machen kann (sofern man den Vergleich schön in eine eigene Methode gepackt hat).
Um ein Bild "virtuell" zu speichern, kann man einen ByteArrayOutputStream verwenden, grob sowas wie
Hätte da noch eine Frage zum vergleichen. Ich speichere mom jeden momentanen Screenshot in pixel[][] und das Bild zuvor in pixel2[][]. Dann vergleiche ich die beiden. Aber wenn ein Unterschied festgestellt wird, was muss ich dann machen?? Wenn ich dann ein pixel3[][] nehme und dort die Werte drin speichere ist schonmal das erste Problem, dass ich die Größe vorher nicht weiß...
Wie schon mehrfach gesagt: Das kann man beliebig ausgefeilt machen. Im einfachsten Fall speichert man sich für seine beiden Arrays die kleinste und größte Position, an der ein Unterschied gefunden wurde
Code:
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = -1;
int maxY = -1;
for (x...)
{
for (y...)
{
if (differentAt(x,y))
{
minX = Math.min(minX, x);
...usw...
}
}
}
Dann hat man am ende Das Rechteck (minX,minY) - (maxX, maxY) in dem "irgendwas" unterschiedlich ist. Das kann man dann übertragen. Natürlich ist das "schlecht", wenn sich zufällig genau der obere Linke und der Untere Rechte Pixel geändert haben: Man überträgt ALLES, obwohl nur 2 Pixel unterschiedlich sind ... da kann man sich dann was überlegen, wie man z.B. rausfinden kann, wie man die Bereiche, die aufgrund einer Änderung übertragen werden, sinnvoll wählt. Z.B. könnte man das Bild in 10x10 Kacheln einteilen, und jede Kachel übertragen, in der sich was geändert hat...