# Kamerabild bleibt hängen



## 1342 (4. Sep 2010)

Hallo Java Freunde,

ich hab hier ein kleines Problem. Ich betreibe eine WLAN-Kamera und habe zur Wiedergabe des Livestreams und zur Steuerung ein Programm geschrieben.
Das Problem ist nun dass das Bild sich kurzzeitig aufhängt und nach 5-10sek wieder läuft.

Hier hab ich mal die Fehlerausgabe:


```
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0x0b 0x01
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0x00 0x61
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0xe3 0xfc
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0x00 0x70
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0x96 0xdd
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
com.sun.image.codec.jpeg.ImageFormatException: Not a JPEG file: starts with 0x0b 0x01
	at sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(Native Method)
	at sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(Unknown Source)
	at wlankamera.MJPG.readJPG(MJPG.java:193)
	at wlankamera.MJPG.readMJPGStream(MJPG.java:183)
	at wlankamera.MJPG.readStream(MJPG.java:159)
	at wlankamera.MJPG.run(MJPG.java:241)
	at java.lang.Thread.run(Unknown Source)
```

*Hier ist der Quellcode meines Programmes:*


```
package wlankamera; // Klasse gehört zum Paket wlankamera

//Import der benötigten Pakete
import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;

//Die Klasse wird erweiter durch JPanel und ist abgeleitet von Runnable
public class MJPG extends JPanel implements Runnable
{
	// Attribute definieren
	public boolean useMJPGStream = true;
	public boolean connected = false;
	private boolean initCompleted = false; 
	public String jpgURL;
	public String mjpgURL;
	private String username;
	private String password;  
	private String base64authorization = null;		
	private Image image = null;
	public Dimension imageSize = null;
	DataInputStream dis;
	HttpURLConnection huc = null;
	
		
	public MJPG (String Daten[]) // Konstruktor
	{	
		// Übergebene Daten werden den Variablen zugewiesen
		mjpgURL = "http://"+Daten[0]+"/videostream.cgi";
		jpgURL = "http://"+Daten[0]+"/videostream.cgi";
		username = Daten[4];
		password = Daten[1];
		
			
		// Benutze Benutzer und Passwort nur wenn sie gegeben sind
		if(username == null || password == null) // Wenn eine der Variablen leer ist
		{
			System.out.println("Kein Benutzer angegeben!"); // Gibt eine Meldung in der Konsole aus
		}
		else
		{
			// Ruft eine Methode auf und speichert deren Rückgabewert in eine Variable
			base64authorization = this.encodeUsernameAndPasswordInBase64(username, password);
		}
	}
		
	// Verschlüsselt Benutzer und Passwort
	private String encodeUsernameAndPasswordInBase64(String usern, String psswd)
	{
		String s = usern + ":" + psswd; // Benutzername und Passwort in eine Variable schreiben   
		String encs = new sun.misc.BASE64Encoder().encode(s.getBytes()); // Verschlüsselung des Strings	    
		return "Basic " + encs; // Wert zurückgeben
	}

	// Verbindung zur Kamera aufbauen
	public void connect()
	{
		try // Versuche
		{
			URL u = new URL(useMJPGStream?mjpgURL:jpgURL); // Ein neues URL objekt wird erstellt
			// Es wird eine URL Verbindung mit speziellen HTTP Methoden erzeugt
			huc = (HttpURLConnection) u.openConnection();
				
			// Wenn die Verschlüsselung stattgefunden hat			
			if(base64authorization != null) // Wenn die Variable ungleich null ist
			{
				huc.setDoInput(true); // Benutze die URLConnection als Eingabe benutzt
				// Benutzer und Passwort benutzen
				huc.setRequestProperty("Authorization",base64authorization);
				huc.connect(); // Die Verbindung wird geöffnet  
			}
			
			InputStream is = huc.getInputStream(); // Es wird von der geöffneten Verbindung gelesen
			connected = true; // Wert der Variable setzen
			BufferedInputStream bis = new BufferedInputStream(is); // Ein Lesepuffer wird verwendet
			// Stellt Routinen zur Verfügung, mit denen Werte der Standarddatentypen aus
			// einem Stream gelesen werden können
			dis = new DataInputStream(bis);
			
			if (!initCompleted) // Wenn Variable false ist
			{
				initDisplay(); // Methode aufrufen
			}
		}
		// Bei einem Fehler wird nochmals probiert eine Verbindung herzustellen
		catch(IOException e) // Wird ausgeführt wenn ein Fehler stattgefunden hat
		{
			try // Versuche
			{
				huc.disconnect(); // HTTPURLConnection trennen
				Thread.sleep(60); // Thread schlafen lassen
			}
			catch(InterruptedException ie) // Beim einem Fehler
			{
				huc.disconnect(); // // HTTPURLConnection trennen
				connect(); // Methode aufrufen
			}
			connect(); // Methode aufrufen
		}
		catch(Exception e) // Bei einem Fehler
		{					
		}
	}

	// Anzeige einstellen
	public void initDisplay()
	{
		if (useMJPGStream) // Wenn der MJPG Stream verwendet wird
		{
			readMJPGStream(); // Methode aufrufen
		}
		else // Wenn der JPG Bilder verwendet werden
		{
			readJPG(); // Methode aufrufen
			disconnect(); // Methode aufrufen
		}
		imageSize = new Dimension(image.getWidth(this), image.getHeight(this)); // Bildgröße wird ermittelt
		setPreferredSize(imageSize); // Größe des JPanel wird gesetzt
		initCompleted = true; // Variable wird auf true gesetzt
	}

	// DataInputStream trennen
	public void disconnect()
	{
		try // Versuche
		{
			if(connected) // Wenn Verbindung zur Kamera vorhanden
			{
				dis.close(); // DataInputStream wird geschlossen
				connected = false; // Variable wird buttonauf false gesetzt
			}
		}
		catch(Exception e) // Bei einem Fehler
		{			
		}
	}

	// Bild auf JPanel zeichnen
	public void paint(Graphics g)
	{
		if (image != null) // Wenn Bild in Variable gespeichert
		{
			g.drawImage(image, 0, 0, this); // Bild auf das Panel setzen
		}
	}

	// Methode um ständig den Stream zu lesen
	public void readStream()
	{
		try // Versuche
		{
			if (useMJPGStream) // Wenn MJPG Stream verwendet wird
			{
				while(true) // Endlosschleife
				{
					readMJPGStream(); // Methode aufrufen
					repaint(); // Bild neu zeichnen
				}
			}
			else // Wenn JPG Bilder verwendet werden
			{
				while(true) // Endlosschleife
				{
					connect(); // Methode aufrufen
					readJPG(); // Methode aufrufen
					repaint(); // Methode aufrufen
					disconnect(); // Methode aufrufen
				}
			}
		}
		catch(Exception e) // Bei einem Fehler
		{
		}
	}

	// Bild aus dem Stream lesen
	public void readMJPGStream()
	{
		readLine(4,dis); // Verwirft die ersten 4 Linien 
		readJPG(); // Methode aufrufen
		readLine(1,dis); // Verwirft die letzte Linie
	}

	// Liest das eingebettete Bild
	public void readJPG()
	{
		try // Versuche
		{
			JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(dis); // JPEG Dekoder erstellen
			image = decoder.decodeAsBufferedImage(); // Bild als BufferedImage in Variable speichern
		}
		catch(Exception e) // Bei einem Fehler wird folgender Code ausgeführt
		{
			e.printStackTrace(); // Fehler buttonauf Konsole ausgeben
			//disconnect(); // Methode aufrufen
		}
	}

	// Liest die Linien heraus
	public void readLine(int n, DataInputStream dis)
	{
		for (int i=0; i<n; i++) // Wird so oft ausgeführt so viele Linien man heraus schneiden will
		{
			readLine(dis); // Methode aufrufen
		}
	}
	
	// Zeilen lesen
	public void readLine(DataInputStream dis)
	{
		try // Versuche
		{
			boolean end = false; // Deklaration
			String lineEnd = "\n"; // Zeichen für das Ende der Linie
			byte[] lineEndBytes = lineEnd.getBytes(); // String in Bytes umwandeln
			byte[] byteBuf = new byte[lineEndBytes.length]; // Länge von lineEndBytes

			while(!end) // Solange end = false
			{
				dis.read(byteBuf,0,lineEndBytes.length); // Ausschnitt aus dem Stream lesen
				String t = new String(byteBuf); // Gelesenes in String schreiben
				if(t.equals(lineEnd)) // Wenn Zeilenende erreicht
				{
					end = true; // Variable aus true setzen
				}
			}
		}
		catch(Exception e) // Wird bei einem Fehler ausgeführt
		{
			e.printStackTrace(); // Fehler auf Konsole ausgeben
		}
	}

	// Hauptmethode wird beim Starten des Threads ausgeführt
	public void run()
	{
		connect(); // Methode aufrufen
		readStream(); // Methode aufrufen
	}

	// Getter Methode für die Screenshot-Funktion
	public Image getImage()
	{
		return image; // Variable image zurückgeben
	}	
}
```

Suche seit Tagen eine Lösung und finde keine, ihr seid meine letzte Hoffnung.

mfg 1342


----------



## Gast2 (4. Sep 2010)

jo - da hat sich die Kamera verschluckt (damit ist sie für mich aus dem "Rennen")


schließe einfach den Verbindung und bau sie neu auf ... die restlichen Daten werden dann einfach verworfen und Du hast mit der nächsten Anfrage gleich wieder ein vernüftiges Bild
außerdem kannst Du auch die Abfragerate ändern - kann sein das Du einfach zu schnell abfragst und die Kamera sich deshalb verschluckt
evt. kannst Du Dir auch die ersten X-Bytes nach dem verschlucken anzeigen lassen - vieleicht sagt Dir die Kamera ja was schief läuft

hand, mogel


----------



## 1342 (4. Sep 2010)

Hm, guter Vorschlag, das ich die Abfragerate ändern könnte.

Nur wie mache ich das?

Hab nirgendwo eine Rate hinterlegt mit der abgefragt wird.

Danke!


----------



## 1342 (7. Sep 2010)

Hallo,

hat jemand ne idee wie man die Abfragerate  ändern kann?

Vielleicht gibt es die Möglichkeit sowas in den Sourcecode den ich gepostet hab einzubinden?!

Gruß


----------



## SlaterB (7. Sep 2010)

du hast Schleifen a la 

```
while(true) // Endlosschleife
                {
                    readMJPGStream(); // Methode aufrufen
                    repaint(); // Bild neu zeichnen
                }
```
bzw. die andere für Einzelbild

direkt nach dem Einlesen eines Bildes fragst du das nächste ab,
mit Thread.sleep(100); könntest du 100 ms Pause machen


----------



## 1342 (7. Sep 2010)

Danke, das war ein guter Tipp!

Es lag allerdings an etwas anderem:


```
// Bild aus dem Stream lesen
    public void readMJPGStream()
    {
        readLine(4,dis); // Verwirft die ersten 4 Linien 
        readJPG(); // Methode aufrufen
        readLine(1,dis); // Verwirft die letzte Linie
    }
```

Ich habe die 4 aus readLine(4,dis) zu einer 3 geändert.
Der Fehler wird zwar immernoch ausgegeben, aber das Bild bleibt nicht mehr hängen, sondern läuft flüssig. 
Kann mir nicht wirklich erklären warum, aber es geht. 

Nun will ich versuchen, den Livestream der Kamera zu speichern, also Aufnehmen.

Hab es mal so probiert:


```
if(Label.equals("Aufnahme")) // Wird ausgeführt wenn "Aufnahme" betätigt wurde
			{	
				try // Versuche
	    		{
				URL url = new URL("http://"+Daten[0]+"/videostream.cgi?&user=benutzer&pwd=passwort");
				URLConnection conn = url.openConnection();
	            InputStreamReader stream = new InputStreamReader(conn.getInputStream());
        	    BufferedReader rd= new BufferedReader( new InputStreamReader(conn.getInputStream()));
        	    FileWriter fw = new FileWriter(Daten[5]);
	            char  buffer[] = new char[0xffff];
	            int   nbytes;

	            while( (nbytes=stream.read(buffer)) != -1) {
	            	fw.write(buffer, 0, nbytes);

	            } 
			}
				catch(IOException e1) // Wird ausgeführt wenn ein Fehler stattgefunden hat
	    		{
	    			  e1.printStackTrace();
	    		}
			}
```

allerdings funktioniert es nicht :-(


----------



## SlaterB (7. Sep 2010)

Reader/ Writer interpretieren Bytes als Chars, als Zeichen(-ketten), das führt bei byte-Daten wie Bildern normalerweise zu Fehlern,
lies und speichere die Daten direkter, wenn du buffer brauchst dann BufferedInputStream auf conn.getInputStream(), byte[] einlesen
und mit FileOutputStream statt FileWriter schreiben

teste evtl. auch ohne Buffer, byte[] liest sowieso große Mengen aufeinmal, Buffer vor allem wenn man viele kleine Mengen einzeln liest/ schreibt


----------



## 1342 (7. Sep 2010)

okay, ich hab es mal ausprobiert:
	
	
	
	





```
if(Label.equals("Aufnahme")) // Wird ausgeführt wenn "Aufnahme" betätigt wurde
			{	
				try // Versuche
	    		{
				URL url = new URL("http://"+Daten[0]+"/videostream.cgi?&user=benutzer&pwd=passwort");
				URLConnection conn = url.openConnection();
				BufferedInputStream stream = new BufferedInputStream(conn.getInputStream());
        	    FileOutputStream fos = new FileOutputStream(Daten[5]);
	            char  buffer[] = new char[0xffff];
	            int   nbytes;

	            while( (nbytes=stream.read()) != -1) {
	            	fos.write(0);

	            } 
			}
				catch(IOException e1) // Wird ausgeführt wenn ein Fehler stattgefunden hat
	    		{
	    			  e1.printStackTrace();
	    		}
			}
```

Aber es funktioniert leider nicht. Ich bekomme auch immer diese Fehlermeldung:


```
java.io.FileNotFoundException: C:\Users\Ich\Pictures (Zugriff verweigert)
	at java.io.FileOutputStream.open(Native Method)
	at java.io.FileOutputStream.<init>(Unknown Source)
	at java.io.FileOutputStream.<init>(Unknown Source)
	at wlankamera.GUI$aListener.actionPerformed(GUI.java:194)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
```

Ich kann mir auch nicht erklären, warum es heisst: Zugriff verweigert. der Ordner ist freigegeben und man kann im Netzwerk ohne Passwort darauf zugreifen.


----------



## SlaterB (7. Sep 2010)

dein Programm kann vorerst komplett in die Tonne in so einem Fall,
schreibe eine neue einfache Klasse mit main-Methode und versuche dort einfache Testdaten in 
> C:\Users\Ich\Pictures
zu schreiben, geht das?

wenn ja, gibt es bestimmte Umstände zu bedenken, wird das Hauptprogramm nicht einfach per main gestartet sondern in einem WebServer, als Applet oder sonst wie komisch?
wie wäre es erstmal mit einem weniger verfänglichen Verzeichnis wie c:\Temp


----------



## 1342 (7. Sep 2010)

Also einzelne Bilder (Screenshots von der Kamera) kann ich ohne Probleme abspeichern in diesen Ordner.


```
if(Label.equals("Screenshot")) // Wird ausgeführt wenn "Screenshot" betätigt wurde
			{		
				// Getter Methode des Objektes "image" aufrufen und Rückgabewert in Variable speichern
				Image bild = image.getImage();
				
				// Screenshot speichern
				try // Versuche
				{
					Date dt = new Date(); // Datum erzeugen
					// Datumsformat festlegen
					SimpleDateFormat dtformat = new SimpleDateFormat("dd.MM.yyyy 'at' HH.mm.ss");
			        BufferedImage bi = (BufferedImage) bild; // "bild" in BufferedImage umwandeln
			        // Neue Datei erzeugen
			        File outputfile = new File(Daten[5] + "\\" + dtformat.format(dt) + ".jpg");
			        ImageIO.write(bi, "jpg", outputfile); // Inhalt von "bi" in Datei schreiben
			    }
				catch (IOException exe) // Wird im Fehlerfall ausgeführt
			    {
			    }
```

Das Problem ist denke ich, dass ich nicht weiss wie ich den Video-Livestream als MJPEG speichern kann und deswegen mit Lösungen, die ich mir im Netz zusammengesucht habe, rumpfusche ;(


----------



## SlaterB (7. Sep 2010)

dann versuchst du anscheinend, in ein Verzeichnis zu speichern,
statt
> new FileOutputStream(Daten[5]);
schreibe
> new FileOutputStream(Daten[5]+"\\mydata.bytes");


----------



## 1342 (9. Sep 2010)

oh super! Danke, das hat funktioniert!

Nun wird eine neue Datei in dem Verzeichnis erzeugt. Das Problem ist nur dass mein Programm nun komplett hängen bleibt wenn ich den button aufnahme betätige.

und das video, welches gespeichert wurde kann ich dann leider auch nicht wiedergeben.

Aber immerhin mal ein schritt vorwärts


----------



## Gast2 (9. Sep 2010)

1342 hat gesagt.:


> Nun wird eine neue Datei in dem Verzeichnis erzeugt. Das Problem ist nur dass mein Programm nun komplett hängen bleibt wenn ich den button aufnahme betätige.


dann nimm Dir mal die Insel und arbeite das Thema Threads und GUI in dem Teil durch



> und das video, welches gespeichert wurde kann ich dann leider auch nicht wiedergeben.


Du speicherst auch kein Video sondern ein einzelnes Bild

hand, mogel


----------



## 1342 (9. Sep 2010)

Hallo Mogel, mein Freund 

Die Insel liegt vor mir! Ich schau die ganze zeit schon rein, allerdings kann ich leider keine zusammenhänge zwischen meinen problemen und dem inhalt der insel erkennen. Ich bin leider noch kein java spezialist sondern ein anfänger.

ich finde dort nichts über videos oder livestreams und wie man diese speichert.leider.

desweiteren bin ich mir nicht sicher ob ich wirklich nur ein bild speichere.
denn wenn sobald ich den button aufnahme betätige, kann ich in meinen ordner gehen, wo das "video"gespeichert wird, und zusehen wie die Größe der neuen Datei zunimmt, bis ich das Programm mit dem Taskmanager beende, weil nichts mehr reagiert.
Und die Größe dieser Datei entspricht eher dem eines videos stett einem Bild?????

aber ich werde weiter in der Insel nach einer Lösung suchen.....


----------



## Gast2 (9. Sep 2010)

1342 hat gesagt.:


> ich finde dort nichts über videos oder livestreams und wie man diese speichert.leider.


da wird auch nicht wirklich was über Videos drinnen stehen ... daher sollest Du Dich da um Dein anderes Problem, das Blockieren der GUI, kümmern -> Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 16.25 AWT, Swing und die Threads



> desweiteren bin ich mir nicht sicher ob ich wirklich nur ein bild speichere.


gut - ich inzwischen auch nicht ... da ja wohl die Datei immer größer wird ... habe mich aber mit Videos unter Java noch nicht beschäftigt ... unter .NET nutze ich (mehr oder weniger) die API


----------

