Video über UDP übertragen - Spiderlinker/HS-Harz_Multimedia-Infrastrukturen GitHub Wiki

Ausgangssituation

Es soll das Videobild der Webcam von einem Rechner (Server) auf einen anderen Rechner (Client) übertragen und dort angezeigt werden. Hierzu muss das Webcam-Bild angefragt und über das Netzwerk übertragen werden.

Als Protokoll soll UDP verwendet werden.

Möglichkeiten von Java

Java bietet die Möglichkeit zum Senden von Daten über UDP. Hierfür stellt es einen sog. DatagramSocket bereit, über den DatagramPackets verschickt und empfangen werden können.

Für die Übertragung muss eine Client-Server-Struktur geschaffen werden.

  • Der Server soll hierbei das Videobild der Webcam an einen festgelegten Port des Clients senden.
  • Der Client lauscht auf den festgelegten Port und soll das vom Server verschickte Videobild empfangen und als Bild darstellen.

Bemerkung zur technischen Umsetzung: Damit die zu übertragenden Daten (und damit einhergehend das zu versendende UDP-Paket) nicht zu groß werden, soll das Kamerabild vor der Übertragung komprimiert werden. Hierfür bietet sich die von Java bereitgestellte Methode ImageIO.write(image, formatName, output) an, die ein Bild bspw. in ein JPG umwandeln kann.

Technische Umsetzung

Wie bereits erwähnt, soll eine Client-Server-Architektur geschaffen werden. Der Server fragt in regelmäßigen Abständen das Kamerabild ab, konvertiert dieses und sendet es in einem UDP-Paket an eine spezifizierte Adresse (des Clients). Der Client lauscht auf diese festgelegte Adresse, liest permanent die empfangenen Daten ein und stellt diese dar.

Server

BufferedImage imageToSend = getImageFromWebcam();

if(imageToSend == null) {
  // Fehler vermeiden. null-Objekte sollen ignoriert werden
  // Andernfalls besteht die Gefahr, dass eine NPE ausgelöst wird
  return;
}

// In diesen ByteArrayStream soll das konvertierte Bild gespeichert werden
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

// Das Bild der Webcam soll in ein JPG umgewandelt werden
ImageIO.write(imageToSend, "jpg", outputStream);

byte[] buffer = outputStream.toByteArray();

// DatagramPacket erstellen mit Angabe der Adresse des Clients + Port
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort);

// DatagramPacket mit Webcam-Bild an den Client senden
socket.send(packet);

Client

// Socket lauscht auf den angegebenen Port 
DatagramSocket socket = new DatagramSocket(PORT);

// Der Buffer speichert die eingehenden Daten zwischen.
// Die Größe muss so gewählt werden, dass ein komplettes Bild 
// in diesem Speicher abgelegt werden kann. 
// Bspw. kann MAX_IMAGE_SIZE = 65535 sein
byte buffer[] = new byte[MAX_IMAGE_SIZE];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

// Permanent neue Daten empfangen und die empfangenen Bilder anzeigen
// Dies muss in einem neuen Thread erfolgen, damit die restliche
// Applikation weiterlaufen kann (muss hinzugefügt werden).
while (true) {
  try {
    // Auf den Port lauschen und eingehende Pakete lesen
    socket.receive(packet);
    byte[] data = packet.getData();
	
	// Die empfangenen Daten in einlesen, in ein Bild umwandeln und anzeigen
    try (ByteArrayInputStream inputStream = new ByteArrayInputStream(data)) {
	  // Bild anzeigen. Hier beispielhaft für JavaFX Image
      Platform.runLater(() -> view.setImage(new Image(inputStream)));
    }
  } catch (IOException e1) {
    e1.printStackTrace();
  }
}

Beachte: while(true) muss natürlich abgeändert werden, sodass das Empfangen und Darstellen von Daten unterbrochen werden kann.

Hilfreiche Quellen

UDP in Java: https://www.baeldung.com/udp-in-java Bilder/Videos über UDP versenden: https://shiffman.net/processing.org/udp/2010/11/13/streaming-video-with-udp-in-processing/ (allerdings nicht direkt umsetzbar, da nicht direkt in Pure-Java geschrieben)