2012-05-02 10 views
5

Ich arbeite an einem iOS-Projekt mit C#. Das Programm nimmt Bilder von einer angeschlossenen Webcam auf und sendet sie per Socket an das iPhone/iPad. Das alles funktioniert einwandfrei und ich kann meinen Stream erfolgreich auf dem Gerät anzeigen lassen.Programm hängt nach dem Aufruf von Dispose()

Aber wenn der Client die Verbindung trennt, muss die Webcam ausgeschaltet werden und in dieser Funktion legt das Programm einfach auf. Keine Fehlermeldungen und keine Ausnahmerufe ... hängt einfach! Ich glaube, es ist ein Problem mit mehreren Threads, aber leider bin ich nicht so erfahren in C#, um eine Lösung zu finden. Ich hoffe, dass hier jemand mich auf dem richtigen Weg bringen ...

Code:
onImageCaptured Funktion:

public void OnImageCaptured(Touchless.Vision.Contracts.IFrameSource frameSource, Touchless.Vision.Contracts.Frame frame, double fps) 
{ 
    _latestFrame = frame.Image; 
    Console.WriteLine("OnImageCaptured"); 
    if (isConnected) 
    { 
     Console.WriteLine("OnImageCaptured - isConnected"); 
     byteArray = new byte[0]; 
     MemoryStream stream = new MemoryStream(); 

     _latestFrame.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg); 
     stream.Close(); 
     byteArray = stream.ToArray(); 

     if (byteArray.Length > 0) 
     { 
      string eof = "<EOF>"; 
      byte[] eofByte = Encoding.ASCII.GetBytes(eof); 
      Console.WriteLine("OnImageCaptured - sendStream"); 
      this.onDataSend(byteArray); 
      this.onDataSend(eofByte); 
      stream.Flush(); 
     } 

     System.Diagnostics.Debugger.Log(0, "1", "\nByte Array Length: " + byteArray.Length.ToString()); 
    } 
    pictureBoxDisplay.Invalidate(); 
} 

definiert wie diese in der Kamera Klasse:

public event EventHandler<CameraEventArgs> OnImageCaptured; 

Und ausgelöst:

OnImageCaptured.Invoke(this, new CameraEventArgs(bitmap, fps)); 

Also diese Funktion - was ich glaube - läuft in einer separaten Bedrohung dar, da die Benutzeroberfläche wird nicht blockiert, wenn die Bilder in kommen

Also die nächsten die Client Trennung in dieser Funktion behandelt wird.

public void onDataSend(byte[] data) 
{ 
    clientReady = false; 
    try 
    { 
     socketWorker.Send(data); 
    } 
    catch (SocketException se) 
    { 
     isConnected = false; 
     Console.WriteLine("Error: Data Write - SocketException"); 
     Console.WriteLine(se.ErrorCode.ToString()); 
     thrashOldCamera() // THIS FUNCTION HANGS THE PROGRAM !! 
     onDisconnectServer(); 

     // onDisconnectServer(); 
    } 
    catch (ObjectDisposedException) 
    { 
     isConnected = false; 
     Console.WriteLine("Error: Data Write - ObjectDisposedException"); 
     // onDisconnectServer(); 
    } 

} 

Client die Verbindung trennt, wird thrashOldCamera() genannt. Funktioniert soweit gut! Jetzt:

private void thrashOldCamera() 
{ 
    Console.WriteLine("TrashOldCamera"); 
    // Trash the old camera 
    if (_frameSource != null) 
    { 
     try 
     { 
      _frameSource.NewFrame -= OnImageCaptured; 
      Console.WriteLine("TrashOldCamera - 1"); 
      _frameSource.Camera.Dispose(); // HERE IT HANGS. IT NEVER GOES PAST HERE !!! 
      Console.WriteLine("TrashOldCamera - 2"); 
      setFrameSource(null); 
      Console.WriteLine("TrashOldCamera - 3"); 
      pictureBoxDisplay.Paint -= new PaintEventHandler(drawLatestImage); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("End Trash Camera Ex: " + ex); 
     } 
    } 
    Console.WriteLine("End Trash Camera"); 
} 

Das Programm hängt an _frameSource.Camera.Dispose();. Wie oben erwähnt, gibt es keinen Fehler oder eine Ausnahme. Es kann ein Problem sein, dass onDataReceive() innerhalb der onImageCapture-Funktion() aufgerufen wird. Ich habe auch eine Schaltfläche zum Formular hinzugefügt, die thrashOldCamera() auslöst und das funktioniert perfekt.

Jede Hilfe/Hinweise werden wirklich geschätzt.

+0

http://channel9.msdn.com/Series/-NET-Debugging-Stater-Kit-for-the-Production-Environment/Diagnosing-Application-Issues-01 –

Antwort

8

Dies nennt sich Deadlock, ein typisches Threading-Problem. Ich sehe nicht, dass Sie explizit auf den UI-Thread irgendwo im Snippet zugreifen, sodass sich der Deadlock möglicherweise in der Kamera-Firmware selbst befindet. Das Kernproblem ist, dass Sie versuchen, die Kamera zu schließen, während Callback immer noch ausgeführt wird, gibt es nicht viel Code, der dazu widerstandsfähig ist. Der Aufruf von Release() kann nicht abgeschlossen werden, bis der Rückruf abgeschlossen ist. Der Rückruf kann jedoch erst abgeschlossen werden, wenn der Aufruf von Release() abgeschlossen ist. Deadlock-Stadt.

Sie müssen Ihren Code neu strukturieren, damit dies nicht passieren kann. Das Aufheben der Kamera zu verzögern ist der Schlüssel, am besten am selben Thread, der die Kamera geöffnet hat. Sie werden es wahrscheinlich lösen, indem Sie es zum Beispiel im FormClosed-Ereignis freigeben. Oder es überhaupt nicht freigeben und es Windows überlassen, Griffe automatisch zu schließen.

0

Suchen Sie das Ereignis, das aufgerufen werden soll, während das Gerät getrennt ist. Schreiben Sie den Code, um die Webcam dort auszuschalten.

+0

ermöglichen müssen Hallo Gijo, nicht genau, was du damit meinst? – Pascal

+0

Möglicherweise gibt es ein Ereignis, mit dem Sie Code zum Ausschalten der Webcam schreiben können. Möglicherweise können Sie die mit dem Steuerelement verfügbare Ereignisliste überprüfen. – MACMAN

+0

Also, was ich gerade bemerkt habe, gibt es eine Funktion namens 'void Dispose()' in der Kamera-Klasse. Wenn ich die Taste zum Drehen der Kamera verwende - was gut funktioniert - wird diese Methode nicht ausgelöst. Wenn ein Client die Verbindung trennt, löst es jedoch diese Funktion aus. – Pascal

3

Sie wissen nicht, ob dies wirklich um einen Kommentar oder eine Antwort sein sollte, aber zumindest kann ich Ihnen unten die richtige Spur zu bekommen.

ich found the source auf die Bibliothek, die Sie verwenden. Dies ist der Inhalt von Camera.Dispose()

public void Dispose() 
{ 
    StopCapture(); 
} 

Ok, da keine große Hilfe, hier ist Camera.StopCapture()

internal void StopCapture() 
{ 
    _cameraMethods.StopCamera(); 
} 

One wieder, keine große Hilfe. _cameraMethods ist eine Art von CameraMethods, die aus der Bibliothek WebCamLib kommt, die eine C++ - Helferbibliothek ist, um mit direkter Show zu kommunizieren.

Hier ist CameraMethods::StopCamera()

void CameraMethods::StopCamera() 
{ 
    if (g_pMediaControl != NULL) 
    { 
     g_pMediaControl->Stop(); 
     g_pMediaControl->Release(); 
     g_pMediaControl = NULL; 
    } 

    g_pfnCaptureCallback = NULL; 

    if (g_pIBaseFilterNullRenderer != NULL) 
    { 
     g_pIBaseFilterNullRenderer->Release(); 
     g_pIBaseFilterNullRenderer = NULL; 
    } 

    if (g_pIBaseFilterSampleGrabber != NULL) 
    { 
     g_pIBaseFilterSampleGrabber->Release(); 
     g_pIBaseFilterSampleGrabber = NULL; 
    } 

    if (g_pIBaseFilterCam != NULL) 
    { 
     g_pIBaseFilterCam->Release(); 
     g_pIBaseFilterCam = NULL; 
    } 

    if (g_pGraphBuilder != NULL) 
    { 
     g_pGraphBuilder->Release(); 
     g_pGraphBuilder = NULL; 
    } 

    if (g_pCaptureGraphBuilder != NULL) 
    { 
     g_pCaptureGraphBuilder->Release(); 
     g_pCaptureGraphBuilder = NULL; 
    } 

    this->activeCameraIndex = -1; 
} 

Es scheint Ihre Ausnahme verwaltet Grenze während des nativen gegessen wird.Ich weiß nicht, wie viel dir das helfen wird, aber zumindest gibt es dir einen Anfang, wo du hinschauen kannst.

Aktivieren Sie das Debuggen von nicht verwaltetem Code und sehen Sie, ob Sie durch die Bibliotheksquelle gehen und sehen können, wo das eigentliche Problem liegt.

enter image description here

Ich mache dies ein Community Wiki, ob jemand, der mehr Erfahrung mit C++/C# Interop hat will diese bearbeiten und mehr hinzuzufügen, was als nächstes zu tun, um das Problem zu debuggen.

+0

Hallo Scott. Danke für deine Antwort. Es bricht sicherlich irgendwo dazwischen, aber das ist weit über meine visuelle C# - C++ Ebene, um eine Lösung zu finden. Ich denke, ich muss nach einem anderen Webcam-Skript suchen, das DirectShow nicht verwendet. – Pascal

0

Gerade falls es damit immer noch ein Thema ist, Verwenden Sie die Touchless.RefreshCameraList von der Kamera trennen können Sie auch die Touchless.CurrentCamera.Dispose hinzufügen wenn ya so wünschen. Sie können immer noch unmannaged Code Debugging

Verwandte Themen