2012-05-02 19 views
5

Sto lavorando a un progetto iOS con C#. Il programma acquisisce le immagini da una webcam collegata e le invia tramite Socket all'iPhone/iPad. Tutto funziona perfettamente e posso visualizzare correttamente il mio stream sul dispositivo.Il programma si blocca dopo aver chiamato Dispose()

Ma quando il client si disconnette, la webcam deve essere disattivata e in questa funzione, il programma si blocca. Nessun messaggio di errore e nessuna chiamata di eccezione ... si blocca! Credo che sia un problema con più thread, ma sfortunatamente non sono così esperto in C# per trovare una soluzione. Spero che qualcuno qui mi può portare sulla strada giusta ...

Codice:
funzione onImageCaptured:

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(); 
} 

Definito come questo in classe Camera:

public event EventHandler<CameraEventArgs> OnImageCaptured; 

ed ha innescato:

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

Quindi questa funzione - ciò che credo - viene eseguita in una minaccia separata dal momento che l'interfaccia utente non è bloccato quando le immagini sono in arrivo

Così la prossima la disconnessione cliente viene gestito in questa funzione:.

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 si disconnette, thrashOldCamera() si chiama. Funziona bene finora! Now:

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"); 
} 

Il programma si blocca a _frameSource.Camera.Dispose();. Come detto sopra, non ci sono errori o eccezioni. Potrebbe essere un problema il fatto che onDataReceive() venga chiamato all'interno della funzione onImageCapture(). Ho anche aggiunto un pulsante al modulo che attiva lo thrashOldCamera() e funziona perfettamente.

Qualsiasi aiuto/suggerimento è veramente apprezzato.

+0

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

risposta

8

Questo è chiamato deadlock, un tipico problema di threading. Non ti vedo invocare esplicitamente il thread dell'interfaccia utente in nessun punto dello snippet, in modo che il deadlock si trovi nel firmware della fotocamera stesso. Il problema principale è che si sta tentando di chiudere la telecamera mentre la sua callback è ancora in esecuzione, non c'è un sacco di codice resiliente a questo. La chiamata Release() non può essere completata fino al completamento della richiamata. Ma il callback non può essere completato fino al completamento della chiamata Release(). Deadlock City.

Avrai bisogno di ristrutturare il tuo codice in modo che questo non possa accadere. Ritardare il rilascio della fotocamera è fondamentale, fatto meglio sullo stesso thread che ha aperto la fotocamera. Probabilmente lo risolverai rilasciandolo nell'evento FormClosed, ad esempio. O non rilasciandolo affatto e lasciandolo a Windows per chiudere automaticamente le maniglie.

0

Trova l'evento da richiamare mentre il dispositivo è disconnesso. Scrivi il codice per spegnere la webcam qui.

+0

Ciao Gijo, non sei proprio sicuro di cosa intendi? – Pascal

+0

Potrebbe esserci un evento che è possibile utilizzare per scrivere codice per spegnere la webcam. Potrebbe essere possibile controllare l'elenco eventi disponibile con il controllo. – MACMAN

+0

quindi quello che ho appena notato, c'è una funzione chiamata 'void Dispose()' nella classe Camera. Se uso il pulsante per accendere la fotocamera - che funziona bene - questo metodo non viene attivato. Se un client si disconnette, tuttavia attiva questa funzione di blocco – Pascal

3

Non so se questo dovrebbe essere un commento o una risposta, ma almeno posso farti scendere nella giusta direzione.

I found the source per la libreria che si sta utilizzando. Questo è il contenuto della Camera.Dispose()

public void Dispose() 
{ 
    StopCapture(); 
} 

Ok, non è di grande aiuto là, qui è Camera.StopCapture()

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

Una volta, non molto di aiuto. _cameraMethods è un tipo di CameraMethods che proviene dalla libreria WebCamLib che è una libreria di supporto C++ per comunicare con lo spettacolo diretto.

Ecco 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; 
} 

Sembra che il tuo eccezione viene consumato durante il nativo al confine gestito.Non so quanto questo ti possa aiutare, ma almeno ti dà un primo sguardo su dove guardare.

Abilitare il debug del codice non gestito e vedere se è possibile scorrere l'origine delle Librerie e vedere dove si trova il vero problema.

enter image description here

Sto facendo di questo un wiki comunità se qualcun altro che ha più esperienza con C++/C# interoperabilità vuole modificare questa e aggiungere più di cosa fare per il debug del problema.

+0

Ciao Scott. Grazie per la tua risposta. Sicuramente si rompe da qualche parte, ma questo è molto al di sopra del mio livello visivo C# - C++ per trovare una soluzione. Immagino di dover cercare un altro script di webcam che non usi directShow. – Pascal

0

Nel caso in cui non v'è ancora un problema con esso, utilizzare il Touchless.RefreshCameraList per scollegare dalla fotocamera è anche possibile aggiungere il Touchless.CurrentCamera.Dispose ya se lo desiderano di. Potrebbe ancora essere necessario abilitare il debug del codice non presidiato

Problemi correlati