2012-12-08 13 views
5

Mam ServerSocket i gniazdo skonfigurowane tak, że ServerSocket wysyła strumień obrazów za pomocą ImageIO.write (....), a Socket próbuje je odczytać i zaktualizować JFrame za ich pomocą. Zastanawiałem się, czy ImageIO może wykryć koniec obrazu. (Nie mam absolutnie żadnej wiedzy o formacie JPEG, więc przetestowałem go zamiast tego)Wysyłaj strumień zdjęć za pomocą ImageIO?

Najwyraźniej nie.

Po stronie serwera wysyłałem obrazy w trybie ciągłym za pomocą ImageIO.write (...) w pętli z niektórymi miejscami do spania. Po stronie klienta ImageIO odczytał pierwszy obraz bez problemu, ale przy następnym zwrócono wartość zerową. To jest mylące. Spodziewałem się, że albo zablokuje czytanie pierwszego obrazu (ponieważ myśli, że następny obraz nadal jest częścią tego samego obrazu), albo odniesie sukces podczas czytania wszystkich (ponieważ działa). Co się dzieje? Wygląda na to, że ImageIO wykrywa koniec pierwszego obrazu, ale nie drugi. (Nawiasem mówiąc, obrazy są do siebie podobne) Czy istnieje prosty sposób przesyłania obrazów w ten sposób lub czy muszę stworzyć własny mechanizm, który odczytuje bajty w buforze, dopóki nie osiągnie określonego bajtu lub sekwencji bajtów, w którym momencie odczytuje obraz z bufora?

Jest to przydatna część mojego kodu serwera:

 while(true){ 
      Socket sock=s.accept(); 
      System.out.println("Connection"); 
      OutputStream out=sock.getOutputStream(); 
      while(!socket.isClosed()){ 
       BufferedImage img=//get image 
       ImageIO.write(img, "jpg", out); 
       Thread.sleep(100); 
      } 
      System.out.println("Closed"); 
     } 

A mój kod klienta:

 Socket s=new Socket(InetAddress.getByName("localhost"), 1998); 
     InputStream in=s.getInputStream(); 
     while(!s.isClosed()){ 
      BufferedImage img=ImageIO.read(in); 
      if(img==null)//this is what happens on the SECOND image 
      else // do something useful with the image 
     } 
+0

Jeszcze dziwniejsze: ustawiłem format ImageIO.write na png, i zadziałało (no, w pewnym stopniu, połowa otrzymanych obrazów była zerowa) – DankMemes

+0

Wygląda na to, że będę musiał zaimplementować system buforujący. :( – DankMemes

+1

* "strumień obrazów za pomocą ImageIO.write (....) a Gniazdo próbuje je odczytać i zaktualizować JFrame za ich pomocą." * Jeśli jest to przeznaczone do czatu internetowego lub udostępniania ekranu lub podobnego, uwaga że wymaga strumieni wideo lub inteligentnie zminimalizowanych obrazów (np. przycinanie tylko zmienionego obszaru, dla rzutu ekranu) Wysyłanie pojedynczych obrazów spowoduje, że powstały film będzie przebiegał jak lodowiec (ignorując globalną zmianę klimatu). –

Odpowiedz

4

ImageIO.read(InputStream) stwarza obraz ImageInputStream i wzywa read(ImageInputStream) wewnętrznie. Ta ostatnia metoda została udokumentowana w celu zamknięcia strumienia po zakończeniu odczytu obrazu.

Tak więc, teoretycznie, można po prostu uzyskać ImageReader, samodzielnie utworzyć ImageInputStream i wielokrotnie czytać ImageReader z ImageInputStream.

Poza tym wygląda na to, że ImageInputStream został zaprojektowany do pracy z jednym i tylko jednym obrazem (który może zawierać lub nie zawiera wielu ramek). Jeśli zadzwonisz pod numer ImageReader.read(0) więcej niż raz, za każdym razem przewiniesz do początku (buforowanego) strumienia danych, co spowoduje, że będzie on ciągle wyświetlany. ImageReader.read(1) będzie szukał drugiej klatki w obrazie wielowarstwowym, co oczywiście nie ma sensu w przypadku JPEG.

Może więc możemy utworzyć ImageInputStream, odczytać z niego ImageReader, a następnie utworzyć nowy ImageInputStream do obsługi kolejnych danych obrazu w strumieniu, prawda? Poza tym wygląda na to, że ImageInputStream wykonuje wszystkie rodzaje buforowania, read-ahead i pushback, co sprawia, że ​​dość trudno jest poznać pozycję odczytu opakowanego obiektu InputStream. Następny ImageInputStream rozpocznie odczytywanie danych skądś, ale nie jest to na końcu danych pierwszego obrazu, jak byśmy oczekiwali.

Jedynym sposobem, aby upewnić się, że pozycja podrzędnego strumienia jest zgodna z mark i reset. Ponieważ obrazy mogą być duże, prawdopodobnie będziesz potrzebować BufferedInputStream, aby umożliwić duże readLimit.

Ten pracował dla mnie:

private static final int MAX_IMAGE_SIZE = 50 * 1024 * 1024; 

static void readImages(InputStream stream) 
throws IOException { 
    stream = new BufferedInputStream(stream); 

    while (true) { 
     stream.mark(MAX_IMAGE_SIZE); 

     ImageInputStream imgStream = 
      ImageIO.createImageInputStream(stream); 

     Iterator<ImageReader> i = 
      ImageIO.getImageReaders(imgStream); 
     if (!i.hasNext()) { 
      logger.log(Level.FINE, "No ImageReaders found, exiting."); 
      break; 
     } 

     ImageReader reader = i.next(); 
     reader.setInput(imgStream); 

     BufferedImage image = reader.read(0); 
     if (image == null) { 
      logger.log(Level.FINE, "No more images to read, exiting."); 
      break; 
     } 

     logger.log(Level.INFO, 
      "Read {0,number}\u00d7{1,number} image", 
      new Object[] { image.getWidth(), image.getHeight() }); 

     long bytesRead = imgStream.getStreamPosition(); 

     stream.reset(); 
     stream.skip(bytesRead); 
    } 
} 
0

Choć może nie jest optymalny sposób to zrobić poniższy kod będzie cię obok wystawia posiadające. Jak poprzednia odpowiedź zauważyła, że ​​ImageIO nie opuszcza strumienia na końcu obrazu, to znajdzie drogę do następnego obrazu.

int imageCount = in.read(); 
for (int i = 0; i < imageCount; i ++){ 
    BufferedImage img = ImageIO.read(in); 
    while (img == null){img = ImageIO.read(in);} 
    //Do what ever with img 
} 
0

Uderzyłem ten sam problem i znalazłem ten post. Komentarz @VGR zainspirował mnie do zagłębienia się w problem, w końcu zdałem sobie sprawę, że ImageIO nie może sobie poradzić z zestawem obrazów w tym samym strumieniu. Więc stworzyłem rozwiązanie (w Scala, przepraszam) i napisałem post na blogu z pewnymi szczegółami i wewnętrznymi informacjami.

http://blog.animatron.com/post/80779366767/a-fix-for-imageio-making-animated-gifs-from-streaming

może to pomoże komuś, jak również.