Webcam-Viewer für Windows Mobile PDA

02. Mai 2008 von Werner Mager · Gelesen: 39903 · heute: 1

Mit einen Windows Mobile PDA mit Wlan kann man zwar auf die Webseiten von IP-Kameras zugreifen, einen Livestream kann man so aber leider nicht sehen. Auch ist die Darstellung meist suboptimal und Vollbild erst recht nicht möglich. Das hier beschriebene Programm umgeht das Problem, in dem direkt die Bilddaten (im Jpeg-Format) von der IP Webcam abgerufen und angezeigt werden. Auch Vollbild ist möglich.
UPDATE: In der Version 1.1 ist nun die Speichernutzung optimiert. Siehe unten.

IP-Kameras

Als Bildadresse empfiehlt sich eine Bildquelle mit einer Auflösung von 320×240 Pixel. Bei Mobotix-Kameras findet man diese z.B. unter /cgi-bin/image.jpg?config&size=320×240 und bei Axis-Kameras unter /axis-cgi/jpg/image.cgi?resolution=320×240.

Hier ein Beispiel, man beachte, dass das Bild “Live” ist:

Die Url dieses Bildes ist:
http://legocamera.marshall.edu/axis-cgi/jpg/image.cgi?resolution=320×240

Weitere IP-Kameras kann man sehr einfach über Google finden, wie das geht ist in etlichen Blogs erklärt (einfach mal nach “google webcam finden” suchen).

Programmierung des Webcam-Viewers

Nun müssen die Bildfolgen der IP-Kamera von unserem Programm geladen und in einer PictureBox angezeigt werden. Zum Abruf der Bilder wird ein Webrequest verwendet. Dabei ist zu beachten, dass dieser die Exception “Der Server hat eine Protokollverletzung ausgeführt.. Section=ResponseHeader Detail=Auf CR muss LF folgen” wirft, wenn man nicht in der Application Config useUnsafeHeaderParsing=”true” setzt. (Dazu später mehr).

// Request the Image from the server and get the response stream
HttpWebRequest request = (HttpWebRequest)(WebRequest.Create(url));
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();

Aus dem Response-Stream können nun die Bilddaten gelesen werden. Die Klasse Bitmap erzeugt uns dabei ein Objekt, das wir direkt in einer PictureBox darstellen können:

Bitmap bmp = new Bitmap(stream);
pictureBox1.Image = bmp;

Um die Bilder in der Vollbild Darstellung um 90 Grad zu rotieren, habe ich auf eine Funktion von Fredrik Bornander zurückgegriffen, die er in einem Artikel auf Codeproject veröffentlicht hat:

Fast Image Rotation For .NET Compact Framework

Hiermit erhalten wir für die Vollbilddarstellung ein rotiertes Bild:

Bitmap bmp2 = new Bitmap(bmp.Height, bmp.Width);
InternalRotateImage(rotationAngle, bmp, bmp2);
pictureBox1.Image = bmp2;

Um eine bewegte Bildfolge zu erhalten, wird einfach ein Bild nach dem anderen von der WebCam angefordert. Damit die Anwendung noch bedienbar bleibt, erfolgt dies in einem Thread:

void PeriodicLoadImage() {
  running = true;
  bool readOk = true;
  while (!stop && readOk) {
    readOk = GetOneImage();
  }
  running = false;
}
 
new Thread(new ThreadStart(PeriodicLoadImage)).Start();

Bei der Verwendung von Threads entstehen jedoch ein paar Tücken, da Windows-Controls nicht “ThreadSave” sind. Um beim aktualisieren des Bildes keine “CrossThread”-Exception auszulösen, muss statt der direkten Zuweisung eine Methode verwendet werden, die “InvokeRequiered” abfragt:

delegate void SetImageDelegate(Bitmap bmp);
 
private void SetImage(Bitmap bmp) {
  if (pictureBox1.InvokeRequired) {
    pictureBox1.Invoke(new SetImageDelegate(SetImage), new Object[] { bmp });
  } else {
    pictureBox1.Image = bmp;
  }
}

Das Problem mit der Exception “Protokollverletzung”

In der Definition des Http-Protokolles ist festgelegt, dass die Header-Zeilen, die ein Webserver zurück gibt, durch die 2 Zeichen CR-LF abgeschlossen werden müssen. Leider halten sich nicht alle Webserver daran, insbesondere bei den Webservern in den IP-Kameras wird nur ein CR zurück gegeben. Microsoft hat im .Net Framework 2.0 eine Überprüfung eingebaut, so dass ein WebRequest eine Exception wirft, wenn der Server kein LF zurück gibt.

Diese Verhalten kann man aber steuern, in dem man eine Config-Datei mit folgendem Inhalt anlegt:

<?xml version=”1.0encoding=”utf-8?>
  <configuration>
    <system.net>
      <settings>
        <httpWebRequest useUnsafeHeaderParsing="true" />
      </settings>
    </system.net>
  </configuration>

Mit ein paar Tricks kann man diese Einstellung auch programmatisch setzten, wie z.B. hier beschrieben ist:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=296969&SiteID=1

Leider funktioniert dies nicht im .Net Compact Framework. Wenn man die App.config im Visual Studio Project hinzufügt, wird sie automatisch beim Build mit abgelegt. Nur was passiert, wenn der User nur die Excutable unserer Anwendung kopiert? Für diesen Fall habe ich eine Methode vorgesehen, die einfach eine Config-Datei anlegt:

private void VerifyApplicationConfig() {
  string file = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
  file += @"\WebcamViewer.exe.config";
  if (file.StartsWith(@"file:\")) {
    file = file.Substring(@"file:\".Length);
  }
  try {
    if (!File.Exists(file)) {
      StreamWriter writer = new StreamWriter(file, true);
      string AppConfig = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
      "<configuration>" +
      "<system.net>" +
      "<settings>" +
      "<httpWebRequest useUnsafeHeaderParsing=\"true\" />" +
      "</settings>" +
      "</system.net>" +
      "</configuration>";
      writer.Write(AppConfig);
      writer.Close();
    }
  } catch { }
}

Diese Methode muss nur einmalig vor dem ersten Zugriff auf Klassen aus system.net aufgerufen werden. Ein geeigneter Platz ist z.B. der Konstruktor der Haupt-Form.

Die fertige Anwendung
Mit ein bisschen Fine tuning entsteht so eine handliche Anwendung, um auf Webcams mit einem PDA zuzugreifen. Hier der komplette Sourcecode zum Download:

UPDATE: Webcam Viewer Sourcen (Für Visual Studio 2005 Professional)

Und für alle nicht-Programmier auch noch die ausführbare Datei:

UPDATE: Webcam Viewer

Zur Ausführung wird das .Net Compact Framework 2.0 auf dem PDA benötigt. Sollte es nicht standardmäßig vorhanden sein (z.B. auf älteren PDAs), kann es von Microsoft heruntergeladen werden:

http://www.microsoft.com/downloads/details.aspx?FamilyID=9655156b-356b-4a2c-857c-e62f50ae9a55&displaylang=de

UPDATE
Dank dem Tip von Markus K. bin ich darauf gekommen dass die Anwendung unter bestimmten Umständen recht viel Speicher beansprucht bzw. der Garbage Collector die Bitmaps nicht sofort recyclet. Mit Hilfe von Sascha Dorenbeck (”Mister Disposable”) konnte ich die Sache so optimeren, dass es nun rund läuft, vielen Dank noch mal :)

2 Antworten zu “Webcam-Viewer für Windows Mobile PDA”

  1. Captain Future sagt:

    Danke für diese coole Anwendung, sie ist echt nützlich!

  2. Fredrik Bornander sagt:

    Interessante Artikel und eine coole Anwendung.
    Es frohe mich dass Sie gefunden haben, eine Verwendung für mein Umsetzung.

    And I really am sorry about my lousy German, I hope you can make out what I was trying to say :)

Hinterlasse eine Antwort